magic cancellation and Protection (trunk only)

Magic cancellation comes from some types of worn armor and has a
value of 0 through 3.  A non-zero value guards against some forms of
monster magic attacks (most notably, level drain by vampires and wraiths
and lycanthropy from werecritter bites).  This reduces the effectiveness
of mc a moderate amount (the new values happen to be the same as those
adopted by the Spork variant):
 chance to block various touch effects
  mc  old     new
   1  34.67%  30%
   2  67.33%  60%
   3  98%     90%

    This also makes the Protection intrinsic (strictly speaking, extrinsic)
be the only way to attain an mc factor of 3.  Cloak of protection is the
only way to get mc 3 from a single item.  Otherwise you need an mc 2 item
and a ring of protection (or one of the recently modified quest artifacts).

     Cancellation factor for elven and dwarvish mithril coats and for
robes and oilskin cloaks is reduced from 3 to 2; for elven cloak and
cloak of magic resistance from 3 to 1 (play balance; they're valuable
even without magic cancellation); for dwarven and orcish cloaks and
clocks of invisibility and displacement and for cornuthaum (wizard hat)
from 2 to 1.  Plate mail and crystal plate mail stay at 2.  A variety of
suits which were at 0 are increased to 1; leather jacket and dragon
scales/scale mail stay at 0 (the latter for play balance rather than for
the amount of your body that's covered).

     Having extrinsic protection will increase mc by 1 (unless it's
already 3).  That's obtained by wearing a cloak of protection (where the
increase is redundant), a ring (or two) of protection (even if conferring
a negative AC amount), or wearing the Mitre of Holiness or wielding the
Tsurugi of Muramasa.  Having multiple sources doesn't make the benefit
cumulative; it's just +1.

     Intrinsic protection (bought from priest, gained from prayer, gained
from eating rings of protection while polymorphed into metallivore, or
temporary while spell of protection is active) doesn't increase mc from
armor but does provide minimum mc 1 instead of naked 0 (play balance
again; buying it is too easy to let it increase mc 1 or 2 to 2 or 3).
(Extrinsic protection is a superset; its +1 bonus also increases 0 to 1.)

    TODO: add an amulet of protection so player has another option for
extrinsic protection.
This commit is contained in:
nethack.rankin
2011-04-07 20:59:40 +00:00
parent 33d9b71311
commit 5bd6ba0d1c
5 changed files with 65 additions and 55 deletions
+2
View File
@@ -353,6 +353,8 @@ spellcasting monsters' spell selection became less likely to choose harder
Eye of the Aethiopica, Eyes of the Overworld, and Sceptre of Might must be Eye of the Aethiopica, Eyes of the Overworld, and Sceptre of Might must be
worn or wielded rather than just carried to convey magic resistance worn or wielded rather than just carried to convey magic resistance
Mitre of Holiness and Tsurugi of Muramasa convey Protection when worn/wielded Mitre of Holiness and Tsurugi of Muramasa convey Protection when worn/wielded
effectiveness of magic cancellation by worn armor has been reduced
Protection improves the effectiveness of magic cancellation
Platform- and/or Interface-Specific Fixes Platform- and/or Interface-Specific Fixes
+1 -1
View File
@@ -719,7 +719,7 @@ mdamagem(magr, mdef, mattk)
/* cancellation factor is the same as when attacking the hero */ /* cancellation factor is the same as when attacking the hero */
armpro = magic_negation(mdef); armpro = magic_negation(mdef);
cancelled = magr->mcan || !((rn2(3) >= armpro) || !rn2(50)); cancelled = magr->mcan || !(rn2(10) >= 3 * armpro);
switch(mattk->adtyp) { switch(mattk->adtyp) {
case AD_DGST: case AD_DGST:
+44 -35
View File
@@ -819,44 +819,53 @@ int
magic_negation(mon) magic_negation(mon)
struct monst *mon; struct monst *mon;
{ {
struct obj *armor; struct obj *o;
int armpro = 0; long wearmask;
int armpro, mc = 0;
boolean is_you = (mon == &youmonst), gotprot = FALSE;
armor = (mon == &youmonst) ? uarm : which_armor(mon, W_ARM); for (o = is_you ? invent : mon->minvent; o; o = o->nobj) {
if (armor && armpro < objects[armor->otyp].a_can) /* a_can field is only applicable for armor (which must be worn) */
armpro = objects[armor->otyp].a_can; if ((o->owornmask & W_ARMOR) != 0L) {
armor = (mon == &youmonst) ? uarmc : which_armor(mon, W_ARMC); armpro = objects[o->otyp].a_can;
if (armor && armpro < objects[armor->otyp].a_can) if (armpro > mc) mc = armpro;
armpro = objects[armor->otyp].a_can; }
armor = (mon == &youmonst) ? uarmh : which_armor(mon, W_ARMH); /* if we've already confirmed Protection, skip additional checks */
if (armor && armpro < objects[armor->otyp].a_can) if (gotprot) continue;
armpro = objects[armor->otyp].a_can;
/* armor types for shirt, gloves, shoes, and shield don't currently /* omit W_SWAPWEP+W_QUIVER; W_ART+W_ARTI handled by protects() */
provide any magic cancellation but we might as well be complete */ wearmask = W_ARMOR | W_RING | W_AMUL | W_TOOL;
#ifdef TOURIST if (o->oclass == WEAPON_CLASS || is_weptool(o)) wearmask |= W_WEP;
armor = (mon == &youmonst) ? uarmu : which_armor(mon, W_ARMU); if (protects(o, ((o->owornmask & wearmask) != 0L) ? TRUE : FALSE))
if (armor && armpro < objects[armor->otyp].a_can) gotprot = TRUE;
armpro = objects[armor->otyp].a_can; }
#endif
armor = (mon == &youmonst) ? uarmg : which_armor(mon, W_ARMG);
if (armor && armpro < objects[armor->otyp].a_can)
armpro = objects[armor->otyp].a_can;
armor = (mon == &youmonst) ? uarmf : which_armor(mon, W_ARMF);
if (armor && armpro < objects[armor->otyp].a_can)
armpro = objects[armor->otyp].a_can;
armor = (mon == &youmonst) ? uarms : which_armor(mon, W_ARMS);
if (armor && armpro < objects[armor->otyp].a_can)
armpro = objects[armor->otyp].a_can;
#ifdef STEED /* extrinsic Protection increases mc factor */
/* this one is really a stretch... */ if (!gotprot) {
armor = (mon == &youmonst) ? 0 : which_armor(mon, W_SADDLE); /* in case hero has extrinsic protection from some other source */
if (armor && armpro < objects[armor->otyp].a_can) if (is_you && EProtection) gotprot = TRUE;
armpro = objects[armor->otyp].a_can; /* high priests have innate intrinsic protection which is as
#endif strong as extrinsic protection */
if (mon->data == &mons[PM_HIGH_PRIEST]) gotprot = TRUE;
}
/* extrinsic Protection increases mc by 1 */
if (gotprot && mc < 3)
mc += 1;
return armpro; /* intrinsic Protection is weaker than Extrinsic (play balance;
obtaining divine protection is too easy) */
if (!gotprot) {
if (is_you && ((HProtection && u.ublessed > 0) || u.uspellprot))
gotprot = TRUE;
/* aligned priests and angels have innate intrinsic Protection */
if (mon->data == &mons[PM_ALIGNED_PRIEST] || is_minion(mon->data))
gotprot = TRUE;
}
/* intrinsic Protection confers minimum mc 1 instead of 0 */
if (gotprot && mc < 1)
mc = 1;
return mc;
} }
/* /*
@@ -913,7 +922,7 @@ hitmu(mtmp, mattk)
* armor's special magic protection. Otherwise just use !mtmp->mcan. * armor's special magic protection. Otherwise just use !mtmp->mcan.
*/ */
armpro = magic_negation(&youmonst); armpro = magic_negation(&youmonst);
uncancelled = !mtmp->mcan && ((rn2(3) >= armpro) || !rn2(50)); uncancelled = !mtmp->mcan && (rn2(10) >= 3 * armpro);
permdmg = 0; permdmg = 0;
/* Now, adjust damages via resistances or specific attacks */ /* Now, adjust damages via resistances or specific attacks */
+17 -18
View File
@@ -1,5 +1,4 @@
/* NetHack 3.5 objects.c $Date$ $Revision$ */ /* NetHack 3.5 objects.c $Date$ $Revision$ */
/* SCCS Id: @(#)objects.c 3.5 2006/12/14 */
/* Copyright (c) Mike Threepoint, 1989. */ /* Copyright (c) Mike Threepoint, 1989. */
/* NetHack may be freely redistributed. See license for details. */ /* NetHack may be freely redistributed. See license for details. */
@@ -307,7 +306,7 @@ HELM("fedora", (char *)0,
1, 0, 0, 0, 0, 3, 1,10, 0, CLOTH, CLR_BROWN), 1, 0, 0, 0, 0, 3, 1,10, 0, CLOTH, CLR_BROWN),
HELM("cornuthaum", "conical hat", HELM("cornuthaum", "conical hat",
0, 1, CLAIRVOYANT, 0, 1, CLAIRVOYANT,
3, 1, 4, 80,10, 2, CLOTH, CLR_BLUE), 3, 1, 4, 80,10, 1, CLOTH, CLR_BLUE),
HELM("dunce cap", "conical hat", HELM("dunce cap", "conical hat",
0, 1, 0, 3, 1, 4, 1,10, 0, CLOTH, CLR_BLUE), 0, 1, 0, 3, 1, 4, 1,10, 0, CLOTH, CLR_BLUE),
HELM("dented pot", (char *)0, HELM("dented pot", (char *)0,
@@ -371,33 +370,33 @@ ARMOR("crystal plate mail", (char *)0,
1, 0, 1, 0, 10, 5, 450, 820, 3, 2, ARM_SUIT, GLASS, CLR_WHITE), 1, 0, 1, 0, 10, 5, 450, 820, 3, 2, ARM_SUIT, GLASS, CLR_WHITE),
#ifdef TOURIST #ifdef TOURIST
ARMOR("bronze plate mail", (char *)0, ARMOR("bronze plate mail", (char *)0,
1, 0, 1, 0, 25, 5, 450, 400, 4, 0, ARM_SUIT, COPPER, HI_COPPER), 1, 0, 1, 0, 25, 5, 450, 400, 4, 1, ARM_SUIT, COPPER, HI_COPPER),
#else #else
ARMOR("bronze plate mail", (char *)0, ARMOR("bronze plate mail", (char *)0,
1, 0, 1, 0, 35, 5, 450, 400, 4, 0, ARM_SUIT, COPPER, HI_COPPER), 1, 0, 1, 0, 35, 5, 450, 400, 4, 1, ARM_SUIT, COPPER, HI_COPPER),
#endif #endif
ARMOR("splint mail", (char *)0, ARMOR("splint mail", (char *)0,
1, 0, 1, 0, 62, 5, 400, 80, 4, 1, ARM_SUIT, IRON, HI_METAL), 1, 0, 1, 0, 62, 5, 400, 80, 4, 1, ARM_SUIT, IRON, HI_METAL),
ARMOR("banded mail", (char *)0, ARMOR("banded mail", (char *)0,
1, 0, 1, 0, 72, 5, 350, 90, 4, 0, ARM_SUIT, IRON, HI_METAL), 1, 0, 1, 0, 72, 5, 350, 90, 4, 1, ARM_SUIT, IRON, HI_METAL),
ARMOR("dwarvish mithril-coat", (char *)0, ARMOR("dwarvish mithril-coat", (char *)0,
1, 0, 0, 0, 10, 1, 150, 240, 4, 3, ARM_SUIT, MITHRIL, HI_METAL), 1, 0, 0, 0, 10, 1, 150, 240, 4, 2, ARM_SUIT, MITHRIL, HI_METAL),
ARMOR("elven mithril-coat", (char *)0, ARMOR("elven mithril-coat", (char *)0,
1, 0, 0, 0, 15, 1, 150, 240, 5, 3, ARM_SUIT, MITHRIL, HI_METAL), 1, 0, 0, 0, 15, 1, 150, 240, 5, 2, ARM_SUIT, MITHRIL, HI_METAL),
ARMOR("chain mail", (char *)0, ARMOR("chain mail", (char *)0,
1, 0, 0, 0, 72, 5, 300, 75, 5, 1, ARM_SUIT, IRON, HI_METAL), 1, 0, 0, 0, 72, 5, 300, 75, 5, 1, ARM_SUIT, IRON, HI_METAL),
ARMOR("orcish chain mail", "crude chain mail", ARMOR("orcish chain mail", "crude chain mail",
0, 0, 0, 0, 20, 5, 300, 75, 6, 1, ARM_SUIT, IRON, CLR_BLACK), 0, 0, 0, 0, 20, 5, 300, 75, 6, 1, ARM_SUIT, IRON, CLR_BLACK),
ARMOR("scale mail", (char *)0, ARMOR("scale mail", (char *)0,
1, 0, 0, 0, 72, 5, 250, 45, 6, 0, ARM_SUIT, IRON, HI_METAL), 1, 0, 0, 0, 72, 5, 250, 45, 6, 1, ARM_SUIT, IRON, HI_METAL),
ARMOR("studded leather armor", (char *)0, ARMOR("studded leather armor", (char *)0,
1, 0, 0, 0, 72, 3, 200, 15, 7, 1, ARM_SUIT, LEATHER, HI_LEATHER), 1, 0, 0, 0, 72, 3, 200, 15, 7, 1, ARM_SUIT, LEATHER, HI_LEATHER),
ARMOR("ring mail", (char *)0, ARMOR("ring mail", (char *)0,
1, 0, 0, 0, 72, 5, 250, 100, 7, 0, ARM_SUIT, IRON, HI_METAL), 1, 0, 0, 0, 72, 5, 250, 100, 7, 1, ARM_SUIT, IRON, HI_METAL),
ARMOR("orcish ring mail", "crude ring mail", ARMOR("orcish ring mail", "crude ring mail",
0, 0, 0, 0, 20, 5, 250, 80, 8, 1, ARM_SUIT, IRON, CLR_BLACK), 0, 0, 0, 0, 20, 5, 250, 80, 8, 1, ARM_SUIT, IRON, CLR_BLACK),
ARMOR("leather armor", (char *)0, ARMOR("leather armor", (char *)0,
1, 0, 0, 0, 82, 3, 150, 5, 8, 0, ARM_SUIT, LEATHER, HI_LEATHER), 1, 0, 0, 0, 82, 3, 150, 5, 8, 1, ARM_SUIT, LEATHER, HI_LEATHER),
ARMOR("leather jacket", (char *)0, ARMOR("leather jacket", (char *)0,
1, 0, 0, 0, 12, 0, 30, 10, 9, 0, ARM_SUIT, LEATHER, CLR_BLACK), 1, 0, 0, 0, 12, 0, 30, 10, 9, 0, ARM_SUIT, LEATHER, CLR_BLACK),
@@ -414,15 +413,15 @@ ARMOR("T-shirt", (char *)0,
CLOAK("mummy wrapping", (char *)0, CLOAK("mummy wrapping", (char *)0,
1, 0, 0, 0, 0, 3, 2, 10, 1, CLOTH, CLR_GRAY), 1, 0, 0, 0, 0, 3, 2, 10, 1, CLOTH, CLR_GRAY),
CLOAK("elven cloak", "faded pall", CLOAK("elven cloak", "faded pall",
0, 1, STEALTH, 8, 0, 10, 60, 9, 3, CLOTH, CLR_BLACK), 0, 1, STEALTH, 8, 0, 10, 60, 9, 1, CLOTH, CLR_BLACK),
CLOAK("orcish cloak", "coarse mantelet", CLOAK("orcish cloak", "coarse mantelet",
0, 0, 0, 8, 0, 10, 40, 10, 2, CLOTH, CLR_BLACK), 0, 0, 0, 8, 0, 10, 40, 10, 1, CLOTH, CLR_BLACK),
CLOAK("dwarvish cloak", "hooded cloak", CLOAK("dwarvish cloak", "hooded cloak",
0, 0, 0, 8, 0, 10, 50, 10, 2, CLOTH, HI_CLOTH), 0, 0, 0, 8, 0, 10, 50, 10, 1, CLOTH, HI_CLOTH),
CLOAK("oilskin cloak", "slippery cloak", CLOAK("oilskin cloak", "slippery cloak",
0, 0, 0, 8, 0, 10, 50, 9, 3, CLOTH, HI_CLOTH), 0, 0, 0, 8, 0, 10, 50, 9, 2, CLOTH, HI_CLOTH),
CLOAK("robe", (char *)0, CLOAK("robe", (char *)0,
1, 1, 0, 3, 0, 15, 50, 8, 3, CLOTH, CLR_RED), 1, 1, 0, 3, 0, 15, 50, 8, 2, CLOTH, CLR_RED),
CLOAK("alchemy smock", "apron", CLOAK("alchemy smock", "apron",
0, 1, POISON_RES, 9, 0, 10, 50, 9, 1, CLOTH, CLR_WHITE), 0, 1, POISON_RES, 9, 0, 10, 50, 9, 1, CLOTH, CLR_WHITE),
CLOAK("leather cloak", (char *)0, CLOAK("leather cloak", (char *)0,
@@ -431,11 +430,11 @@ CLOAK("leather cloak", (char *)0,
CLOAK("cloak of protection", "tattered cape", CLOAK("cloak of protection", "tattered cape",
0, 1, PROTECTION, 9, 0, 10, 50, 7, 3, CLOTH, HI_CLOTH), 0, 1, PROTECTION, 9, 0, 10, 50, 7, 3, CLOTH, HI_CLOTH),
CLOAK("cloak of invisibility", "opera cloak", CLOAK("cloak of invisibility", "opera cloak",
0, 1, INVIS, 10, 0, 10, 60, 9, 2, CLOTH, CLR_BRIGHT_MAGENTA), 0, 1, INVIS, 10, 0, 10, 60, 9, 1, CLOTH, CLR_BRIGHT_MAGENTA),
CLOAK("cloak of magic resistance", "ornamental cope", CLOAK("cloak of magic resistance", "ornamental cope",
0, 1, ANTIMAGIC, 2, 0, 10, 60, 9, 3, CLOTH, CLR_WHITE), 0, 1, ANTIMAGIC, 2, 0, 10, 60, 9, 1, CLOTH, CLR_WHITE),
CLOAK("cloak of displacement", "piece of cloth", CLOAK("cloak of displacement", "piece of cloth",
0, 1, DISPLACED, 10, 0, 10, 50, 9, 2, CLOTH, HI_CLOTH), 0, 1, DISPLACED, 10, 0, 10, 50, 9, 1, CLOTH, HI_CLOTH),
/* shields */ /* shields */
SHIELD("small shield", (char *)0, SHIELD("small shield", (char *)0,
+1 -1
View File
@@ -1356,7 +1356,7 @@ register struct attack *mattk;
armpro = magic_negation(mdef); armpro = magic_negation(mdef);
/* since hero can't be cancelled, only defender's armor applies */ /* since hero can't be cancelled, only defender's armor applies */
negated = !((rn2(3) >= armpro) || !rn2(50)); negated = !(rn2(10) >= 3 * armpro);
if (is_demon(youmonst.data) && !rn2(13) && !uwep if (is_demon(youmonst.data) && !rn2(13) && !uwep
&& u.umonnum != PM_SUCCUBUS && u.umonnum != PM_INCUBUS && u.umonnum != PM_SUCCUBUS && u.umonnum != PM_INCUBUS