1 /* SCCS Id: @(#)artifact.c 3.4 2003/08/11 */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed. See license for details. */
10 STATIC_DCL struct artifact artilist[];
13 * Note: both artilist[] and artiexist[] have a dummy element #0,
14 * so loops over them should normally start at #1. The primary
15 * exception is the save & restore code, which doesn't care about
16 * the contents, just the total size.
19 extern boolean notonhead; /* for long worms */
21 #define get_artifact(o) \
22 (((o)&&(o)->oartifact) ? &artilist[(int) (o)->oartifact] : 0)
24 STATIC_DCL int FDECL(spec_applies, (const struct artifact *,struct monst *));
25 STATIC_DCL int FDECL(arti_invoke, (struct obj*));
26 STATIC_DCL boolean FDECL(Mb_hit, (struct monst *magr,struct monst *mdef,
27 struct obj *,int *,int,BOOLEAN_P,char *));
29 /* The amount added to the victim's total hit points to insure that the
30 victim will be killed even after damage bonus/penalty adjustments.
31 Most such penalties are small, and 200 is plenty; the exception is
32 half physical damage. 3.3.1 and previous versions tried to use a very
33 large number to account for this case; now, we just compute the fatal
34 damage by adding it to 2 times the total hit points instead of 1 time.
35 Note: this will still break if they have more than about half the number
36 of hit points that will fit in a 15 bit integer. */
37 #define FATAL_DAMAGE_MODIFIER 200
40 STATIC_DCL int spec_dbon_applies;
41 STATIC_DCL xchar artidisco[NROFARTIFACTS];
43 /* coordinate effects from spec_dbon() with messages in artifact_hit() */
44 STATIC_OVL int spec_dbon_applies = 0;
46 /* flags including which artifacts have already been created */
47 static boolean artiexist[1+NROFARTIFACTS+1];
48 /* and a discovery list for them (no dummy first entry here) */
49 STATIC_OVL xchar artidisco[NROFARTIFACTS];
51 STATIC_DCL void NDECL(hack_artifacts);
52 STATIC_DCL boolean FDECL(attacks, (int,struct obj *));
54 /* handle some special cases; must be called after u_init() */
59 int alignmnt = aligns[flags.initalign].value;
61 /* Fix up the alignments of "gift" artifacts */
62 for (art = artilist+1; art->otyp; art++)
63 if (art->role == Role_switch && art->alignment != A_NONE)
64 art->alignment = alignmnt;
66 /* Excalibur can be used by any lawful character, not just knights */
67 if (!Role_if(PM_KNIGHT))
68 artilist[ART_EXCALIBUR].role = NON_PM;
70 /* Fix up the quest artifact */
71 if (urole.questarti) {
72 artilist[urole.questarti].alignment = alignmnt;
73 artilist[urole.questarti].role = Role_switch;
78 /* zero out the artifact existence list */
82 (void) memset((genericptr_t) artiexist, 0, sizeof artiexist);
83 (void) memset((genericptr_t) artidisco, 0, sizeof artidisco);
91 bwrite(fd, (genericptr_t) artiexist, sizeof artiexist);
92 bwrite(fd, (genericptr_t) artidisco, sizeof artidisco);
99 mread(fd, (genericptr_t) artiexist, sizeof artiexist);
100 mread(fd, (genericptr_t) artidisco, sizeof artidisco);
101 hack_artifacts(); /* redo non-saved special cases */
108 if (artinum <= 0 || artinum > NROFARTIFACTS) return("");
109 return(artilist[artinum].name);
113 Make an artifact. If a specific alignment is specified, then an object of
114 the appropriate alignment is created from scratch, or 0 is returned if
115 none is available. (If at least one aligned artifact has already been
116 given, then unaligned ones also become eligible for this.)
117 If no alignment is given, then 'otmp' is converted
118 into an artifact of matching type, or returned as-is if that's not 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);''.
123 mk_artifact(otmp, alignment)
124 struct obj *otmp; /* existing object; ignored if alignment specified */
125 aligntyp alignment; /* target alignment, or A_NONE */
127 const struct artifact *a;
129 boolean by_align = (alignment != A_NONE);
130 short o_typ = (by_align || !otmp) ? 0 : otmp->otyp;
131 boolean unique = !by_align && otmp && objects[o_typ].oc_unique;
132 short eligible[NROFARTIFACTS];
134 /* gather eligible artifacts */
135 for (n = 0, a = artilist+1, m = 1; a->otyp; a++, m++)
136 if ((!by_align ? a->otyp == o_typ :
137 (a->alignment == alignment ||
138 (a->alignment == A_NONE && u.ugifts > 0))) &&
139 (!(a->spfx & SPFX_NOGEN) || unique) && !artiexist[m]) {
140 if (by_align && a->race != NON_PM && race_hostile(&mons[a->race]))
141 continue; /* skip enemies' equipment */
142 else if (by_align && Role_if(a->role))
143 goto make_artif; /* 'a' points to the desired one */
148 if (n) { /* found at least one candidate */
149 m = eligible[rn2(n)]; /* [0..n-1] */
152 /* make an appropriate object if necessary, then christen it */
153 make_artif: if (by_align) otmp = mksobj((int)a->otyp, TRUE, FALSE);
154 otmp = oname(otmp, a->name);
158 /* nothing appropriate could be found; return the original object */
159 if (by_align) otmp = 0; /* (there was no original object) */
165 * Returns the full name (with articles and correct capitalization) of an
166 * artifact named "name" if one exists, or NULL, it not.
167 * The given name must be rather close to the real name for it to match.
168 * The object type of the artifact is returned in otyp if the return value
172 artifact_name(name, otyp)
176 register const struct artifact *a;
177 register const char *aname;
179 if(!strncmpi(name, "the ", 4)) name += 4;
181 for (a = artilist+1; a->otyp; a++) {
183 if(!strncmpi(aname, "the ", 4)) aname += 4;
184 if(!strcmpi(name, aname)) {
194 exist_artifact(otyp, name)
196 register const char *name;
198 register const struct artifact *a;
199 register boolean *arex;
202 for (a = artilist+1,arex = artiexist+1; a->otyp; a++,arex++)
203 if ((int) a->otyp == otyp && !strcmp(a->name, name))
209 artifact_exists(otmp, name, mod)
210 register struct obj *otmp;
211 register const char *name;
212 register boolean mod;
214 register const struct artifact *a;
217 for (a = artilist+1; a->otyp; a++)
218 if (a->otyp == otmp->otyp && !strcmp(a->name, name)) {
219 register int m = a - artilist;
220 otmp->oartifact = (char)(mod ? m : 0);
222 if(otmp->otyp == RIN_INCREASE_DAMAGE)
234 int n = SIZE(artiexist);
237 if(artiexist[--n]) a++;
245 spec_ability(otmp, abil)
249 const struct artifact *arti = get_artifact(otmp);
251 return((boolean)(arti && (arti->spfx & abil)));
254 /* used so that callers don't need to known about SPFX_ codes */
259 /* might as well check for this too */
260 if (obj->otyp == LUCKSTONE) return TRUE;
262 return (obj->oartifact && spec_ability(obj, SPFX_LUCK));
265 /* used to check whether a monster is getting reflection from an artifact */
270 const struct artifact *arti = get_artifact(obj);
273 /* while being worn */
274 if ((obj->owornmask & ~W_ART) && (arti->spfx & SPFX_REFLECT))
276 /* just being carried */
277 if (arti->cspfx & SPFX_REFLECT) return TRUE;
286 restrict_name(otmp, name) /* returns 1 if name is restricted for otmp->otyp */
287 register struct obj *otmp;
288 register const char *name;
290 register const struct artifact *a;
291 register const char *aname;
293 if (!*name) return FALSE;
294 if (!strncmpi(name, "the ", 4)) name += 4;
296 /* Since almost every artifact is SPFX_RESTR, it doesn't cost
297 us much to do the string comparison before the spfx check.
298 Bug fix: don't name multiple elven daggers "Sting".
300 for (a = artilist+1; a->otyp; a++) {
301 if (a->otyp != otmp->otyp) continue;
303 if (!strncmpi(aname, "the ", 4)) aname += 4;
304 if (!strcmp(aname, name))
305 return ((boolean)((a->spfx & (SPFX_NOGEN|SPFX_RESTR)) != 0 ||
315 register struct obj *otmp;
317 register const struct artifact *weap;
319 if ((weap = get_artifact(otmp)) != 0)
320 return((boolean)(weap->attk.adtyp == adtyp));
327 register struct obj *otmp;
329 register const struct artifact *weap;
331 if ((weap = get_artifact(otmp)) != 0)
332 return((boolean)(weap->defn.adtyp == adtyp));
336 /* used for monsters */
338 protects(adtyp, otmp)
342 register const struct artifact *weap;
344 if ((weap = get_artifact(otmp)) != 0)
345 return (boolean)(weap->cary.adtyp == adtyp);
350 * a potential artifact has just been worn/wielded/picked-up or
351 * unworn/unwielded/dropped. Pickup/drop only set/reset the W_ART mask.
354 set_artifact_intrinsic(otmp,on,wp_mask)
355 register struct obj *otmp;
360 register const struct artifact *oart = get_artifact(otmp);
366 /* effects from the defn field */
367 dtyp = (wp_mask != W_ART) ? oart->defn.adtyp : oart->cary.adtyp;
370 mask = &EFire_resistance;
371 else if (dtyp == AD_COLD)
372 mask = &ECold_resistance;
373 else if (dtyp == AD_ELEC)
374 mask = &EShock_resistance;
375 else if (dtyp == AD_MAGM)
377 else if (dtyp == AD_DISN)
378 mask = &EDisint_resistance;
379 else if (dtyp == AD_DRST)
380 mask = &EPoison_resistance;
382 if (mask && wp_mask == W_ART && !on) {
383 /* find out if some other artifact also confers this intrinsic */
384 /* if so, leave the mask alone */
385 register struct obj* obj;
386 for(obj = invent; obj; obj = obj->nobj)
387 if(obj != otmp && obj->oartifact) {
388 register const struct artifact *art = get_artifact(obj);
389 if(art->cary.adtyp == dtyp) {
396 if (on) *mask |= wp_mask;
397 else *mask &= ~wp_mask;
400 /* intrinsics from the spfx field; there could be more than one */
401 spfx = (wp_mask != W_ART) ? oart->spfx : oart->cspfx;
402 if(spfx && wp_mask == W_ART && !on) {
403 /* don't change any spfx also conferred by other artifacts */
404 register struct obj* obj;
405 for(obj = invent; obj; obj = obj->nobj)
406 if(obj != otmp && obj->oartifact) {
407 register const struct artifact *art = get_artifact(obj);
412 if (spfx & SPFX_SEARCH) {
413 if(on) ESearching |= wp_mask;
414 else ESearching &= ~wp_mask;
416 if (spfx & SPFX_HALRES) {
417 /* make_hallucinated must (re)set the mask itself to get
418 * the display right */
419 /* restoring needed because this is the only artifact intrinsic
420 * that can print a message--need to guard against being printed
421 * when restoring a game
423 (void) make_hallucinated((long)!on, restoring ? FALSE : TRUE, wp_mask);
425 if (spfx & SPFX_ESP) {
426 if(on) ETelepat |= wp_mask;
427 else ETelepat &= ~wp_mask;
430 if (spfx & SPFX_STLTH) {
431 if (on) EStealth |= wp_mask;
432 else EStealth &= ~wp_mask;
434 if (spfx & SPFX_REGEN) {
435 if (on) ERegeneration |= wp_mask;
436 else ERegeneration &= ~wp_mask;
438 if (spfx & SPFX_TCTRL) {
439 if (on) ETeleport_control |= wp_mask;
440 else ETeleport_control &= ~wp_mask;
442 if (spfx & SPFX_WARN) {
445 EWarn_of_mon |= wp_mask;
446 flags.warntype |= spec_m2(otmp);
448 EWarn_of_mon &= ~wp_mask;
449 flags.warntype &= ~spec_m2(otmp);
453 if (on) EWarning |= wp_mask;
454 else EWarning &= ~wp_mask;
457 if (spfx & SPFX_EREGEN) {
458 if (on) EEnergy_regeneration |= wp_mask;
459 else EEnergy_regeneration &= ~wp_mask;
461 if (spfx & SPFX_HSPDAM) {
462 if (on) EHalf_spell_damage |= wp_mask;
463 else EHalf_spell_damage &= ~wp_mask;
465 if (spfx & SPFX_HPHDAM) {
466 if (on) EHalf_physical_damage |= wp_mask;
467 else EHalf_physical_damage &= ~wp_mask;
469 if (spfx & SPFX_XRAY) {
470 /* this assumes that no one else is using xray_range */
471 if (on) u.xray_range = 3;
472 else u.xray_range = -1;
473 vision_full_recalc = 1;
475 if ((spfx & SPFX_REFLECT) && (wp_mask & W_WEP)) {
476 if (on) EReflecting |= wp_mask;
477 else EReflecting &= ~wp_mask;
480 if(wp_mask == W_ART && !on && oart->inv_prop) {
481 /* might have to turn off invoked power too */
482 if (oart->inv_prop <= LAST_PROP &&
483 (u.uprops[oart->inv_prop].extrinsic & W_ARTI))
484 (void) arti_invoke(otmp);
489 * creature (usually player) tries to touch (pick up or wield) an artifact obj.
490 * Returns 0 if the object refuses to be touched.
491 * This routine does not change any object chains.
492 * Ignores such things as gauntlets, assuming the artifact is not
493 * fooled by such trappings.
496 touch_artifact(obj,mon)
500 register const struct artifact *oart = get_artifact(obj);
501 boolean badclass, badalign, self_willed, yours;
505 yours = (mon == &youmonst);
506 /* all quest artifacts are self-willed; it this ever changes, `badclass'
507 will have to be extended to explicitly include quest artifacts */
508 self_willed = ((oart->spfx & SPFX_INTEL) != 0);
510 badclass = self_willed &&
511 ((oart->role != NON_PM && !Role_if(oart->role)) ||
512 (oart->race != NON_PM && !Race_if(oart->race)));
513 badalign = (oart->spfx & SPFX_RESTR) && oart->alignment != A_NONE &&
514 (oart->alignment != u.ualign.type || u.ualign.record < 0);
515 } else if (!is_covetous(mon->data) && !is_mplayer(mon->data)) {
516 badclass = self_willed &&
517 oart->role != NON_PM && oart != &artilist[ART_EXCALIBUR];
518 badalign = (oart->spfx & SPFX_RESTR) && oart->alignment != A_NONE &&
519 (oart->alignment != sgn(mon->data->maligntyp));
520 } else { /* an M3_WANTSxxx monster or a fake player */
521 /* special monsters trying to take the Amulet, invocation tools or
522 quest item can touch anything except for `spec_applies' artifacts */
523 badclass = badalign = FALSE;
525 /* weapons which attack specific categories of monsters are
526 bad for them even if their alignments happen to match */
527 if (!badalign && (oart->spfx & SPFX_DBONUS) != 0) {
531 tmp.spfx &= SPFX_DBONUS;
532 badalign = !!spec_applies(&tmp, mon);
535 if (((badclass || badalign) && self_willed) ||
536 (badalign && (!yours || !rn2(4)))) {
540 if (!yours) return 0;
541 You("are blasted by %s power!", s_suffix(the(xname(obj))));
542 dmg = d((Antimagic ? 2 : 4), (self_willed ? 10 : 4));
543 Sprintf(buf, "touching %s", oart->name);
544 losehp(dmg, buf, KILLED_BY);
545 exercise(A_WIS, FALSE);
548 /* can pick it up unless you're totally non-synch'd with the artifact */
549 if (badclass && badalign && self_willed) {
550 if (yours) pline("%s your grasp!", Tobjnam(obj, "evade"));
560 /* decide whether an artifact's special attacks apply against mtmp */
562 spec_applies(weap, mtmp)
563 register const struct artifact *weap;
566 struct permonst *ptr;
569 if(!(weap->spfx & (SPFX_DBONUS | SPFX_ATTK)))
570 return(weap->attk.adtyp == AD_PHYS);
572 yours = (mtmp == &youmonst);
575 if (weap->spfx & SPFX_DMONS) {
576 return (ptr == &mons[(int)weap->mtype]);
577 } else if (weap->spfx & SPFX_DCLAS) {
578 return (weap->mtype == (unsigned long)ptr->mlet);
579 } else if (weap->spfx & SPFX_DFLAG1) {
580 return ((ptr->mflags1 & weap->mtype) != 0L);
581 } else if (weap->spfx & SPFX_DFLAG2) {
582 return ((ptr->mflags2 & weap->mtype) || (yours &&
583 ((!Upolyd && (urace.selfmask & weap->mtype)) ||
584 ((weap->mtype & M2_WERE) && u.ulycn >= LOW_PM))));
585 } else if (weap->spfx & SPFX_DALIGN) {
586 return yours ? (u.ualign.type != weap->alignment) :
587 (ptr->maligntyp == A_NONE ||
588 sgn(ptr->maligntyp) != weap->alignment);
589 } else if (weap->spfx & SPFX_ATTK) {
590 struct obj *defending_weapon = (yours ? uwep : MON_WEP(mtmp));
592 if (defending_weapon && defending_weapon->oartifact &&
593 defends((int)weap->attk.adtyp, defending_weapon))
595 switch(weap->attk.adtyp) {
597 return !(yours ? Fire_resistance : resists_fire(mtmp));
599 return !(yours ? Cold_resistance : resists_cold(mtmp));
601 return !(yours ? Shock_resistance : resists_elec(mtmp));
604 return !(yours ? Antimagic : (rn2(100) < ptr->mr));
606 return !(yours ? Poison_resistance : resists_poison(mtmp));
608 return !(yours ? Drain_resistance : resists_drli(mtmp));
610 return !(yours ? Stone_resistance : resists_ston(mtmp));
611 default: impossible("Weird weapon special attack.");
617 /* return the M2 flags of monster that an artifact's special attacks apply against */
622 register const struct artifact *artifact = get_artifact(otmp);
624 return artifact->mtype;
628 /* special attack bonus */
634 register const struct artifact *weap = get_artifact(otmp);
636 /* no need for an extra check for `NO_ATTK' because this will
637 always return 0 for any artifact which has that attribute */
639 if (weap && weap->attk.damn && spec_applies(weap, mon))
640 return rnd((int)weap->attk.damn);
644 /* special damage bonus */
646 spec_dbon(otmp, mon, tmp)
651 register const struct artifact *weap = get_artifact(otmp);
653 if (!weap || (weap->attk.adtyp == AD_PHYS && /* check for `NO_ATTK' */
654 weap->attk.damn == 0 && weap->attk.damd == 0))
655 spec_dbon_applies = FALSE;
657 spec_dbon_applies = spec_applies(weap, mon);
659 if (spec_dbon_applies)
660 return weap->attk.damd ? rnd((int)weap->attk.damd) : max(tmp,1);
664 /* add identified artifact to discoveries list */
671 /* look for this artifact in the discoveries list;
672 if we hit an empty slot then it's not present, so add it */
673 for (i = 0; i < NROFARTIFACTS; i++)
674 if (artidisco[i] == 0 || artidisco[i] == m) {
678 /* there is one slot per artifact, so we should never reach the
679 end without either finding the artifact or an empty slot... */
680 impossible("couldn't discover artifact (%d)", (int)m);
683 /* used to decide whether an artifact has been fully identified */
685 undiscovered_artifact(m)
690 /* look for this artifact in the discoveries list;
691 if we hit an empty slot then it's undiscovered */
692 for (i = 0; i < NROFARTIFACTS; i++)
693 if (artidisco[i] == m)
695 else if (artidisco[i] == 0)
700 /* display a list of discovered artifacts; return their count */
702 disp_artifact_discoveries(tmpwin)
703 winid tmpwin; /* supplied by dodiscover() */
708 for (i = 0; i < NROFARTIFACTS; i++) {
709 if (artidisco[i] == 0) break; /* empty slot implies end of list */
710 if (i == 0) putstr(tmpwin, iflags.menu_headings, "Artifacts");
712 otyp = artilist[m].otyp;
713 Sprintf(buf, " %s [%s %s]", artiname(m),
714 align_str(artilist[m].alignment), simple_typename(otyp));
715 putstr(tmpwin, 0, buf);
726 * Magicbane's intrinsic magic is incompatible with normal
727 * enchantment magic. Thus, its effects have a negative
728 * dependence on spe. Against low mr victims, it typically
729 * does "double athame" damage, 2d4. Occasionally, it will
730 * cast unbalancing magic which effectively averages out to
731 * 4d4 damage (3d4 against high mr victims), for spe = 0.
733 * Prior to 3.4.1, the cancel (aka purge) effect always
734 * included the scare effect too; now it's one or the other.
735 * Likewise, the stun effect won't be combined with either
736 * of those two; it will be chosen separately or possibly
737 * used as a fallback when scare or cancel fails.
739 * [Historical note: a change to artifact_hit() for 3.4.0
740 * unintentionally made all of Magicbane's special effects
741 * be blocked if the defender successfully saved against a
742 * stun attack. As of 3.4.1, those effects can occur but
743 * will be slightly less likely than they were in 3.3.x.]
745 #define MB_MAX_DIEROLL 8 /* rolls above this aren't magical */
746 static const char * const mb_verb[2][4] = {
747 { "probe", "stun", "scare", "cancel" },
748 { "prod", "amaze", "tickle", "purge" },
750 #define MB_INDEX_PROBE 0
751 #define MB_INDEX_STUN 1
752 #define MB_INDEX_SCARE 2
753 #define MB_INDEX_CANCEL 3
755 /* called when someone is being hit by Magicbane */
757 Mb_hit(magr, mdef, mb, dmgptr, dieroll, vis, hittee)
758 struct monst *magr, *mdef; /* attacker and defender */
759 struct obj *mb; /* Magicbane */
760 int *dmgptr; /* extra damage target will suffer */
761 int dieroll; /* d20 that has already scored a hit */
762 boolean vis; /* whether the action can be seen */
763 char *hittee; /* target's name: "you" or mon_nam(mdef) */
765 struct permonst *old_uasmon;
767 boolean youattack = (magr == &youmonst),
768 youdefend = (mdef == &youmonst),
769 resisted = FALSE, do_stun, do_confuse, result;
770 int attack_indx, scare_dieroll = MB_MAX_DIEROLL / 2;
772 result = FALSE; /* no message given yet */
773 /* the most severe effects are less likely at higher enchantment */
775 scare_dieroll /= (1 << (mb->spe / 3));
776 /* if target successfully resisted the artifact damage bonus,
777 reduce overall likelihood of the assorted special effects */
778 if (!spec_dbon_applies) dieroll += 1;
780 /* might stun even when attempting a more severe effect, but
781 in that case it will only happen if the other effect fails;
782 extra damage will apply regardless; 3.4.1: sometimes might
783 just probe even when it hasn't been enchanted */
784 do_stun = (max(mb->spe,0) < rn2(spec_dbon_applies ? 11 : 7));
786 /* the special effects also boost physical damage; increments are
787 generally cumulative, but since the stun effect is based on a
788 different criterium its damage might not be included; the base
789 damage is either 1d4 (athame) or 2d4 (athame+spec_dbon) depending
790 on target's resistance check against AD_STUN (handled by caller)
791 [note that a successful save against AD_STUN doesn't actually
792 prevent the target from ending up stunned] */
793 attack_indx = MB_INDEX_PROBE;
794 *dmgptr += rnd(4); /* (2..3)d4 */
796 attack_indx = MB_INDEX_STUN;
797 *dmgptr += rnd(4); /* (3..4)d4 */
799 if (dieroll <= scare_dieroll) {
800 attack_indx = MB_INDEX_SCARE;
801 *dmgptr += rnd(4); /* (3..5)d4 */
803 if (dieroll <= (scare_dieroll / 2)) {
804 attack_indx = MB_INDEX_CANCEL;
805 *dmgptr += rnd(4); /* (4..6)d4 */
808 /* give the hit message prior to inflicting the effects */
809 verb = mb_verb[!!Hallucination][attack_indx];
810 if (youattack || youdefend || vis) {
812 pline_The("magic-absorbing blade %s %s!",
813 vtense((const char *)0, verb), hittee);
814 /* assume probing has some sort of noticeable feedback
815 even if it is being done by one monster to another */
816 if (attack_indx == MB_INDEX_PROBE && !canspotmon(mdef))
817 map_invisible(mdef->mx, mdef->my);
820 /* now perform special effects */
821 switch (attack_indx) {
822 case MB_INDEX_CANCEL:
823 old_uasmon = youmonst.data;
824 /* No mdef->mcan check: even a cancelled monster can be polymorphed
825 * into a golem, and the "cancel" effect acts as if some magical
826 * energy remains in spellcasting defenders to be absorbed later.
828 if (!cancel_monst(mdef, mb, youattack, FALSE, FALSE)) {
833 if (youmonst.data != old_uasmon)
834 *dmgptr = 0; /* rehumanized, so no more damage */
836 You("lose magical energy!");
838 if (u.uen > 0) u.uen--;
842 if (mdef->data == &mons[PM_CLAY_GOLEM])
843 mdef->mhp = 1; /* cancelled clay golems will die */
844 if (youattack && attacktype(mdef->data, AT_MAGC)) {
845 You("absorb magical energy!");
861 if (magr && magr == u.ustuck && sticks(youmonst.data)) {
862 u.ustuck = (struct monst *)0;
863 You("release %s!", mon_nam(magr));
867 if (rn2(2) && resist(mdef, WEAPON_CLASS, 0, NOTELL))
870 monflee(mdef, 3, FALSE, (mdef->mhp > *dmgptr));
872 if (!resisted) do_stun = FALSE;
876 do_stun = TRUE; /* (this is redundant...) */
880 if (youattack && (mb->spe == 0 || !rn2(3 * abs(mb->spe)))) {
881 pline_The("%s is insightful.", verb);
882 /* pre-damage status */
887 /* stun if that was selected and a worse effect didn't occur */
890 make_stunned((HStun + 3), FALSE);
893 /* avoid extra stun message below if we used mb_verb["stun"] above */
894 if (attack_indx == MB_INDEX_STUN) do_stun = FALSE;
896 /* lastly, all this magic can be confusing... */
897 do_confuse = !rn2(12);
900 make_confused(HConfusion + 4, FALSE);
905 if (youattack || youdefend || vis) {
906 (void) upstart(hittee); /* capitalize */
908 pline("%s %s!", hittee, vtense(hittee, "resist"));
909 shieldeff(youdefend ? u.ux : mdef->mx,
910 youdefend ? u.uy : mdef->my);
912 if ((do_stun || do_confuse) && flags.verbose) {
916 if (do_stun) Strcat(buf, "stunned");
917 if (do_stun && do_confuse) Strcat(buf, " and ");
918 if (do_confuse) Strcat(buf, "confused");
919 pline("%s %s %s%c", hittee, vtense(hittee, "are"),
920 buf, (do_stun && do_confuse) ? '!' : '.');
927 /* Function used when someone attacks someone else with an artifact
928 * weapon. Only adds the special (artifact) damage, and returns a 1 if it
929 * did something special (in which case the caller won't print the normal
930 * hit message). This should be called once upon every artifact attack;
931 * dmgval() no longer takes artifact bonuses into account. Possible
932 * extension: change the killer so that when an orc kills you with
933 * Stormbringer it's "killed by Stormbringer" instead of "killed by an orc".
936 artifact_hit(magr, mdef, otmp, dmgptr, dieroll)
937 struct monst *magr, *mdef;
940 int dieroll; /* needed for Magicbane and vorpal blades */
942 boolean youattack = (magr == &youmonst);
943 boolean youdefend = (mdef == &youmonst);
944 boolean vis = (!youattack && magr && cansee(magr->mx, magr->my))
945 || (!youdefend && cansee(mdef->mx, mdef->my))
946 || (youattack && u.uswallow && mdef == u.ustuck && !Blind);
947 boolean realizes_damage;
949 static const char you[] = "you";
952 Strcpy(hittee, youdefend ? you : mon_nam(mdef));
954 /* The following takes care of most of the damage, but not all--
955 * the exception being for level draining, which is specially
956 * handled. Messages are done in this function, however.
958 *dmgptr += spec_dbon(otmp, mdef, *dmgptr);
960 if (youattack && youdefend) {
961 impossible("attacking yourself with weapon?");
965 realizes_damage = (youdefend || vis ||
966 /* feel the effect even if not seen */
967 (youattack && mdef == u.ustuck));
969 /* the four basic attacks: fire, cold, shock and missiles */
970 if (attacks(AD_FIRE, otmp)) {
972 pline_The("fiery blade %s %s%c",
973 !spec_dbon_applies ? "hits" :
974 (mdef->data == &mons[PM_WATER_ELEMENTAL]) ?
975 "vaporizes part of" : "burns",
976 hittee, !spec_dbon_applies ? '.' : '!');
977 if (!rn2(4)) (void) destroy_mitem(mdef, POTION_CLASS, AD_FIRE);
978 if (!rn2(4)) (void) destroy_mitem(mdef, SCROLL_CLASS, AD_FIRE);
979 if (!rn2(7)) (void) destroy_mitem(mdef, SPBOOK_CLASS, AD_FIRE);
980 if (youdefend && Slimed) burn_away_slime();
981 return realizes_damage;
983 if (attacks(AD_COLD, otmp)) {
985 pline_The("ice-cold blade %s %s%c",
986 !spec_dbon_applies ? "hits" : "freezes",
987 hittee, !spec_dbon_applies ? '.' : '!');
988 if (!rn2(4)) (void) destroy_mitem(mdef, POTION_CLASS, AD_COLD);
989 return realizes_damage;
991 if (attacks(AD_ELEC, otmp)) {
993 pline_The("massive hammer hits%s %s%c",
994 !spec_dbon_applies ? "" : "! Lightning strikes",
995 hittee, !spec_dbon_applies ? '.' : '!');
996 if (!rn2(5)) (void) destroy_mitem(mdef, RING_CLASS, AD_ELEC);
997 if (!rn2(5)) (void) destroy_mitem(mdef, WAND_CLASS, AD_ELEC);
998 return realizes_damage;
1000 if (attacks(AD_MAGM, otmp)) {
1001 if (realizes_damage)
1002 pline_The("imaginary widget hits%s %s%c",
1003 !spec_dbon_applies ? "" :
1004 "! A hail of magic missiles strikes",
1005 hittee, !spec_dbon_applies ? '.' : '!');
1006 return realizes_damage;
1009 if (attacks(AD_STUN, otmp) && dieroll <= MB_MAX_DIEROLL) {
1010 /* Magicbane's special attacks (possibly modifies hittee[]) */
1011 return Mb_hit(magr, mdef, otmp, dmgptr, dieroll, vis, hittee);
1014 if (!spec_dbon_applies) {
1015 /* since damage bonus didn't apply, nothing more to do;
1016 no further attacks have side-effects on inventory */
1020 /* We really want "on a natural 20" but Nethack does it in */
1021 /* reverse from AD&D. */
1022 if (spec_ability(otmp, SPFX_BEHEAD)) {
1023 if (otmp->oartifact == ART_TSURUGI_OF_MURAMASA && dieroll == 1) {
1024 wepdesc = "The razor-sharp blade";
1025 /* not really beheading, but so close, why add another SPFX */
1026 if (youattack && u.uswallow && mdef == u.ustuck) {
1027 You("slice %s wide open!", mon_nam(mdef));
1028 *dmgptr = 2 * mdef->mhp + FATAL_DAMAGE_MODIFIER;
1032 /* allow normal cutworm() call to add extra damage */
1036 if (bigmonst(mdef->data)) {
1038 You("slice deeply into %s!",
1041 pline("%s cuts deeply into %s!",
1042 Monnam(magr), hittee);
1046 *dmgptr = 2 * mdef->mhp + FATAL_DAMAGE_MODIFIER;
1047 pline("%s cuts %s in half!", wepdesc, mon_nam(mdef));
1048 otmp->dknown = TRUE;
1051 if (bigmonst(youmonst.data)) {
1052 pline("%s cuts deeply into you!",
1053 magr ? Monnam(magr) : wepdesc);
1058 /* Players with negative AC's take less damage instead
1059 * of just not getting hit. We must add a large enough
1060 * value to the damage so that this reduction in
1061 * damage does not prevent death.
1063 *dmgptr = 2 * (Upolyd ? u.mh : u.uhp) + FATAL_DAMAGE_MODIFIER;
1064 pline("%s cuts you in half!", wepdesc);
1065 otmp->dknown = TRUE;
1068 } else if (otmp->oartifact == ART_VORPAL_BLADE &&
1069 (dieroll == 1 || mdef->data == &mons[PM_JABBERWOCK])) {
1070 static const char * const behead_msg[2] = {
1072 "%s decapitates %s!"
1075 if (youattack && u.uswallow && mdef == u.ustuck)
1077 wepdesc = artilist[ART_VORPAL_BLADE].name;
1079 if (!has_head(mdef->data) || notonhead || u.uswallow) {
1081 pline("Somehow, you miss %s wildly.",
1084 pline("Somehow, %s misses wildly.",
1087 return ((boolean)(youattack || vis));
1089 if (noncorporeal(mdef->data) || amorphous(mdef->data)) {
1090 pline("%s slices through %s %s.", wepdesc,
1091 s_suffix(mon_nam(mdef)),
1092 mbodypart(mdef,NECK));
1095 *dmgptr = 2 * mdef->mhp + FATAL_DAMAGE_MODIFIER;
1096 pline(behead_msg[rn2(SIZE(behead_msg))],
1097 wepdesc, mon_nam(mdef));
1098 otmp->dknown = TRUE;
1101 if (!has_head(youmonst.data)) {
1102 pline("Somehow, %s misses you wildly.",
1103 magr ? mon_nam(magr) : wepdesc);
1107 if (noncorporeal(youmonst.data) || amorphous(youmonst.data)) {
1108 pline("%s slices through your %s.",
1109 wepdesc, body_part(NECK));
1112 *dmgptr = 2 * (Upolyd ? u.mh : u.uhp)
1113 + FATAL_DAMAGE_MODIFIER;
1114 pline(behead_msg[rn2(SIZE(behead_msg))],
1116 otmp->dknown = TRUE;
1117 /* Should amulets fall off? */
1122 if (spec_ability(otmp, SPFX_DRLI)) {
1125 if(otmp->oartifact == ART_STORMBRINGER)
1126 pline_The("%s blade draws the life from %s!",
1130 pline("%s draws the life from %s!",
1131 The(distant_name(otmp, xname)),
1134 if (mdef->m_lev == 0) {
1135 *dmgptr = 2 * mdef->mhp + FATAL_DAMAGE_MODIFIER;
1139 mdef->mhpmax -= drain;
1142 if (drain) healup(drain, 0, FALSE, FALSE);
1145 } else { /* youdefend */
1146 int oldhpmax = u.uhpmax;
1149 You_feel("an %s drain your life!",
1150 otmp->oartifact == ART_STORMBRINGER ?
1151 "unholy blade" : "object");
1152 else if (otmp->oartifact == ART_STORMBRINGER)
1153 pline_The("%s blade drains your life!",
1156 pline("%s drains your life!",
1157 The(distant_name(otmp, xname)));
1158 losexp("life drainage");
1159 if (magr && magr->mhp < magr->mhpmax) {
1160 magr->mhp += (oldhpmax - u.uhpmax)/2;
1161 if (magr->mhp > magr->mhpmax) magr->mhp = magr->mhpmax;
1169 static NEARDATA const char recharge_type[] = { ALLOW_COUNT, ALL_CLASSES, 0 };
1170 static NEARDATA const char invoke_types[] = { ALL_CLASSES, 0 };
1171 /* #invoke: an "ugly check" filters out most objects */
1176 register struct obj *obj;
1178 obj = getobj(invoke_types, "invoke");
1180 if (obj->oartifact && !touch_artifact(obj, &youmonst)) return 1;
1181 return arti_invoke(obj);
1186 register struct obj *obj;
1188 register const struct artifact *oart = get_artifact(obj);
1190 if(!oart || !oart->inv_prop) {
1191 if(obj->otyp == CRYSTAL_BALL)
1192 use_crystal_ball(obj);
1194 pline(nothing_happens);
1198 if(oart->inv_prop > LAST_PROP) {
1199 /* It's a special power, not "just" a property */
1200 if(obj->age > monstermoves) {
1201 /* the artifact is tired :-) */
1202 You_feel("that %s %s ignoring you.",
1203 the(xname(obj)), otense(obj, "are"));
1204 /* and just got more so; patience is essential... */
1205 obj->age += (long) d(3,10);
1208 obj->age = monstermoves + rnz(100);
1210 switch(oart->inv_prop) {
1214 pseudo = zeroobj; /* neither cursed nor blessed */
1215 pseudo.otyp = SCR_TAMING;
1216 (void) seffects(&pseudo);
1220 int healamt = (u.uhpmax + 1 - u.uhp) / 2;
1221 long creamed = (long)u.ucreamed;
1223 if (Upolyd) healamt = (u.mhmax + 1 - u.mh) / 2;
1224 if (healamt || Sick || Slimed || Blinded > creamed)
1225 You_feel("better.");
1227 goto nothing_special;
1229 if (Upolyd) u.mh += healamt;
1230 else u.uhp += healamt;
1232 if(Sick) make_sick(0L,(char *)0,FALSE,SICK_ALL);
1233 if(Slimed) Slimed = 0L;
1234 if (Blinded > creamed) make_blinded(creamed, FALSE);
1238 case ENERGY_BOOST: {
1239 int epboost = (u.uenmax + 1 - u.uen) / 2;
1240 if (epboost > 120) epboost = 120; /* arbitrary */
1241 else if (epboost < 12) epboost = u.uenmax - u.uen;
1243 You_feel("re-energized.");
1247 goto nothing_special;
1252 obj->age = 0; /* don't charge for changing their mind */
1258 struct obj *otmp = getobj(recharge_type, "charge");
1265 b_effect = obj->blessed &&
1266 (Role_switch == oart->role || !oart->role);
1267 recharge(otmp, b_effect ? 1 : obj->cursed ? -1 : 0);
1274 case CREATE_PORTAL: {
1275 int i, num_ok_dungeons, last_ok_dungeon = 0;
1277 extern int n_dgns; /* from dungeon.c */
1278 winid tmpwin = create_nhwindow(NHW_MENU);
1281 any.a_void = 0; /* set all bits to zero */
1283 /* use index+1 (cant use 0) as identifier */
1284 for (i = num_ok_dungeons = 0; i < n_dgns; i++) {
1285 if (!dungeons[i].dunlev_ureached) continue;
1287 add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE,
1288 dungeons[i].dname, MENU_UNSELECTED);
1290 last_ok_dungeon = i;
1292 end_menu(tmpwin, "Open a portal to which dungeon?");
1293 if (num_ok_dungeons > 1) {
1294 /* more than one entry; display menu for choices */
1295 menu_item *selected;
1298 n = select_menu(tmpwin, PICK_ONE, &selected);
1300 destroy_nhwindow(tmpwin);
1301 goto nothing_special;
1303 i = selected[0].item.a_int - 1;
1304 free((genericptr_t)selected);
1306 i = last_ok_dungeon; /* also first & only OK dungeon */
1307 destroy_nhwindow(tmpwin);
1310 * i is now index into dungeon structure for the new dungeon.
1311 * Find the closest level in the given dungeon, open
1312 * a use-once portal to that dungeon and go there.
1313 * The closest level is either the entry or dunlev_ureached.
1316 if(dungeons[i].depth_start >= depth(&u.uz))
1317 newlev.dlevel = dungeons[i].entry_lev;
1319 newlev.dlevel = dungeons[i].dunlev_ureached;
1320 if(u.uhave.amulet || In_endgame(&u.uz) || In_endgame(&newlev) ||
1321 newlev.dnum == u.uz.dnum) {
1322 You_feel("very disoriented for a moment.");
1324 if(!Blind) You("are surrounded by a shimmering sphere!");
1325 else You_feel("weightless for a moment.");
1326 goto_level(&newlev, FALSE, FALSE, FALSE);
1334 struct obj *otmp = mksobj(ARROW, TRUE, FALSE);
1336 if (!otmp) goto nothing_special;
1337 otmp->blessed = obj->blessed;
1338 otmp->cursed = obj->cursed;
1339 otmp->bknown = obj->bknown;
1341 if (otmp->spe < 0) otmp->spe = 0;
1342 otmp->quan += rnd(10);
1343 } else if (obj->cursed) {
1344 if (otmp->spe > 0) otmp->spe = 0;
1346 otmp->quan += rnd(5);
1347 otmp->owt = weight(otmp);
1348 otmp = hold_another_object(otmp, "Suddenly %s out.",
1349 aobjnam(otmp, "fall"), (const char *)0);
1354 long eprop = (u.uprops[oart->inv_prop].extrinsic ^= W_ARTI),
1355 iprop = u.uprops[oart->inv_prop].intrinsic;
1356 boolean on = (eprop & W_ARTI) != 0; /* true if invoked prop just set */
1358 if(on && obj->age > monstermoves) {
1359 /* the artifact is tired :-) */
1360 u.uprops[oart->inv_prop].extrinsic ^= W_ARTI;
1361 You_feel("that %s %s ignoring you.",
1362 the(xname(obj)), otense(obj, "are"));
1363 /* can't just keep repeatedly trying */
1364 obj->age += (long) d(3,10);
1367 /* when turning off property, determine downtime */
1368 /* arbitrary for now until we can tune this -dlc */
1369 obj->age = monstermoves + rnz(100);
1372 if ((eprop & ~W_ARTI) || iprop) {
1374 /* you had the property from some other source too */
1376 You_feel("a surge of power, but nothing seems to happen.");
1379 switch(oart->inv_prop) {
1381 if(on) You_feel("like a rabble-rouser.");
1382 else You_feel("the tension decrease around you.");
1388 } else (void) float_down(I_SPECIAL|TIMEOUT, W_ARTI);
1391 if (BInvis || Blind) goto nothing_special;
1394 Your("body takes on a %s transparency...",
1395 Hallucination ? "normal" : "strange");
1397 Your("body seems to unfade...");
1406 /* WAC return TRUE if artifact is always lit */
1411 return (get_artifact(obj) && obj->oartifact == ART_SUNSWORD);
1414 /* KMH -- Talking artifacts are finally implemented */
1419 register const struct artifact *oart = get_artifact(obj);
1424 /* Is this a speaking artifact? */
1425 if (!oart || !(oart->spfx & SPFX_SPEAK))
1428 line = getrumor(bcsign(obj), buf, TRUE);
1430 line = "NetHack rumors file closed for renovation.";
1431 pline("%s:", Tobjnam(obj, "whisper"));
1432 verbalize("%s", line);
1437 artifact_has_invprop(otmp, inv_prop)
1441 const struct artifact *arti = get_artifact(otmp);
1443 return((boolean)(arti && (arti->inv_prop == inv_prop)));
1446 /* Return the price sold to the hero of a given artifact or unique item */
1451 if (!otmp->oartifact)
1452 return ((long)objects[otmp->otyp].oc_cost);
1453 else if (artilist[(int) otmp->oartifact].cost)
1454 return (artilist[(int) otmp->oartifact].cost);
1456 return (100L * (long)objects[otmp->otyp].oc_cost);