From f2e39539141558b4396d5b93998b1c058b9851e9 Mon Sep 17 00:00:00 2001 From: "nethack.rankin" Date: Fri, 22 Feb 2008 01:44:57 +0000 Subject: [PATCH] vitamin deficiency (trunk only) Implement something suggested a long time ago: eating a disenchanter corpse has a chance to remove an intrinsic. Uses the same routine as nighttime gremlin attacks, which chooses an intrinsic randomly and attempts to remove it, so has no effect if it chooses one the hero lacks. This can be used to remove "aggravate monster" but is much more likely to target something the player wants to keep. [By the way, a lot of potential candidates are missing: sleep, shock, and disintegration resistance and teleport control come immediately to mind.] Also, it has been bugging me that you can get both strength and fire/cold/shock resistance from the same fire/frost/storm giant corpse. The code prevents mind flayer corpses from conferring both intelligence and telepathy, so strength handling was inconsistent (even though it predated mind flayers...). This causes strength boosting to be treated as an extra candidate when selecting an intrinsic to confer, so you'll either get strength or resistance (which might be a no-op) but not both from those giants. And it special cases the other giants to have the same 50% chance for boosting strength, even though the alternative in their case is to do nothing instead of trying to confer something else. Lastly, it now gives a message when you succeed in gaining strength. --- doc/fixes35.0 | 2 + include/extern.h | 2 +- src/attrib.c | 20 ++--- src/eat.c | 207 +++++++++++++++++++++-------------------------- 4 files changed, 106 insertions(+), 125 deletions(-) diff --git a/doc/fixes35.0 b/doc/fixes35.0 index 9d832ea3f..d8d7305f6 100644 --- a/doc/fixes35.0 +++ b/doc/fixes35.0 @@ -282,6 +282,7 @@ while polymorphed, suppress attribute gain/lose earned by pre-poly exercise wizard mode #monpolycontrol prompting asked about "it" when monster was unseen reprompt if player fails to make a menu choice during inventory identification seen eels who were stuck in isolated pools would never re-hide +can no longer get both strength and resistance from eating one giant corpse Platform- and/or Interface-Specific Fixes @@ -398,6 +399,7 @@ shapechangers shouldn't receive starting inventory of their initial shape streamline old ^X output and integrate it with enlightenment feedback; new ^X output includes expanded form of abbreviated bottom line info "killed by X" becomes "killed by a chameleon imitating X" when appropriate +eating disenchanter corpses is now considered risky Platform- and/or Interface-Specific New Features diff --git a/include/extern.h b/include/extern.h index 619c20141..32ba58138 100644 --- a/include/extern.h +++ b/include/extern.h @@ -92,7 +92,7 @@ E void FDECL(retouch_equipment, (int)); /* ### attrib.c ### */ E boolean FDECL(adjattrib, (int,int,int)); -E void FDECL(gainstr, (struct obj *,int)); +E void FDECL(gainstr, (struct obj *,int,BOOLEAN_P)); E void FDECL(losestr, (int)); E void FDECL(poisontell, (int,BOOLEAN_P)); E void FDECL(poisoned, (const char *,int,const char *,int,BOOLEAN_P)); diff --git a/src/attrib.c b/src/attrib.c index d402fc21d..7b4757c25 100644 --- a/src/attrib.c +++ b/src/attrib.c @@ -160,18 +160,20 @@ adjattrib(ndx, incr, msgflg) } void -gainstr(otmp, incr) - register struct obj *otmp; - register int incr; +gainstr(otmp, incr, givemsg) +struct obj *otmp; +int incr; +boolean givemsg; { - int num = 1; + int num = incr; - if(incr) num = incr; - else { - if(ABASE(A_STR) < 18) num = (rn2(4) ? 1 : rnd(6) ); + if (!num) { + if (ABASE(A_STR) < 18) num = (rn2(4) ? 1 : rnd(6)); else if (ABASE(A_STR) < STR18(85)) num = rnd(10); + else num = 1; } - (void) adjattrib(A_STR, (otmp && otmp->cursed) ? -num : num, TRUE); + (void) adjattrib(A_STR, (otmp && otmp->cursed) ? -num : num, + givemsg ? -1 : 1); } void @@ -191,7 +193,7 @@ losestr(num) /* may kill you; cause may be poison or monster like 'a' */ u.uhpmax -= 6; } } - (void) adjattrib(A_STR, -num, TRUE); + (void) adjattrib(A_STR, -num, 1); } static const struct poison_effect_message { diff --git a/src/eat.c b/src/eat.c index 7f4e32f02..7faac3a6a 100644 --- a/src/eat.c +++ b/src/eat.c @@ -720,7 +720,7 @@ fix_petrification() * be an intrinsic property.) * It would be very easy to make the intrinsics not try to give you one * that you already had by checking to see if you have it in - * intrinsic_possible() instead of givit(). + * intrinsic_possible() instead of givit(), but we're not that nice. */ /* intrinsic_possible() returns TRUE iff a monster can give an intrinsic. */ @@ -729,92 +729,68 @@ intrinsic_possible(type, ptr) int type; register struct permonst *ptr; { + int res = 0; + switch (type) { - case FIRE_RES: + case FIRE_RES: + res = (ptr->mconveys & MR_FIRE) != 0; #ifdef DEBUG - if (ptr->mconveys & MR_FIRE) { - debugpline("can get fire resistance"); - return(TRUE); - } else return(FALSE); -#else - return(ptr->mconveys & MR_FIRE); + if (res) debugpline("can get fire resistance"); #endif - case SLEEP_RES: + break; + case SLEEP_RES: + res = (ptr->mconveys & MR_SLEEP) != 0; #ifdef DEBUG - if (ptr->mconveys & MR_SLEEP) { - debugpline("can get sleep resistance"); - return(TRUE); - } else return(FALSE); -#else - return(ptr->mconveys & MR_SLEEP); + if (res) debugpline("can get sleep resistance"); #endif - case COLD_RES: + break; + case COLD_RES: + res = (ptr->mconveys & MR_COLD) != 0; #ifdef DEBUG - if (ptr->mconveys & MR_COLD) { - debugpline("can get cold resistance"); - return(TRUE); - } else return(FALSE); -#else - return(ptr->mconveys & MR_COLD); + if (res) debugpline("can get cold resistance"); #endif - case DISINT_RES: + break; + case DISINT_RES: + res = (ptr->mconveys & MR_DISINT) != 0; #ifdef DEBUG - if (ptr->mconveys & MR_DISINT) { - debugpline("can get disintegration resistance"); - return(TRUE); - } else return(FALSE); -#else - return(ptr->mconveys & MR_DISINT); + if (res) debugpline("can get disintegration resistance"); #endif - case SHOCK_RES: /* shock (electricity) resistance */ + break; + case SHOCK_RES: /* shock (electricity) resistance */ + res = (ptr->mconveys & MR_ELEC) != 0; #ifdef DEBUG - if (ptr->mconveys & MR_ELEC) { - debugpline("can get shock resistance"); - return(TRUE); - } else return(FALSE); -#else - return(ptr->mconveys & MR_ELEC); + if (res) debugpline("can get shock resistance"); #endif - case POISON_RES: + break; + case POISON_RES: + res = (ptr->mconveys & MR_POISON) != 0; #ifdef DEBUG - if (ptr->mconveys & MR_POISON) { - debugpline("can get poison resistance"); - return(TRUE); - } else return(FALSE); -#else - return(ptr->mconveys & MR_POISON); + if (res) debugpline("can get poison resistance"); #endif - case TELEPORT: + break; + case TELEPORT: + res = can_teleport(ptr); #ifdef DEBUG - if (can_teleport(ptr)) { - debugpline("can get teleport"); - return(TRUE); - } else return(FALSE); -#else - return(can_teleport(ptr)); + if (res) debugpline("can get teleport"); #endif - case TELEPORT_CONTROL: + break; + case TELEPORT_CONTROL: + res = control_teleport(ptr); #ifdef DEBUG - if (control_teleport(ptr)) { - debugpline("can get teleport control"); - return(TRUE); - } else return(FALSE); -#else - return(control_teleport(ptr)); + if (res) debugpline("can get teleport control"); #endif - case TELEPAT: + break; + case TELEPAT: + res = telepathic(ptr); #ifdef DEBUG - if (telepathic(ptr)) { - debugpline("can get telepathy"); - return(TRUE); - } else return(FALSE); -#else - return(telepathic(ptr)); + if (res) debugpline("can get telepathy"); #endif - default: - return(FALSE); + break; + default: + /* res stays 0 */ + break; } - /*NOTREACHED*/ + return res; } /* givit() tries to give you an intrinsic based on the monster's level @@ -1085,6 +1061,14 @@ register int pm; polyself(0); } break; + case PM_DISENCHANTER: + /* picks an intrinsic at random and removes it; there's + no feedback if hero already lacks the chosen ability */ +#ifdef DEBUG + debugpline("using attrcurse to strip an intrinsic"); +#endif + attrcurse(); + break; case PM_MIND_FLAYER: case PM_MASTER_MIND_FLAYER: if (ABASE(A_INT) < ATTRMAX(A_INT)) { @@ -1093,66 +1077,59 @@ register int pm; (void) adjattrib(A_INT, 1, FALSE); break; /* don't give them telepathy, too */ } - } - else { + } else { pline("For some reason, that tasted bland."); } - /* fall through to default case */ - default: { - register struct permonst *ptr = &mons[pm]; + /*FALLTHRU*/ + default: + { + struct permonst *ptr = &mons[pm]; + boolean conveys_STR = is_giant(ptr); int i, count; if (dmgtype(ptr, AD_STUN) || dmgtype(ptr, AD_HALU) || - pm == PM_VIOLET_FUNGUS) { - pline ("Oh wow! Great stuff!"); - (void) make_hallucinated(HHallucination + 200,FALSE,0L); + pm == PM_VIOLET_FUNGUS) { + pline("Oh wow! Great stuff!"); + (void)make_hallucinated(HHallucination + 200L, FALSE, 0L); } - if(is_giant(ptr)) gainstr((struct obj *)0, 0); /* Check the monster for all of the intrinsics. If this * monster can give more than one, pick one to try to give * from among all it can give. * - * If a monster can give 4 intrinsics then you have - * a 1/1 * 1/2 * 2/3 * 3/4 = 1/4 chance of getting the first, - * a 1/2 * 2/3 * 3/4 = 1/4 chance of getting the second, - * a 1/3 * 3/4 = 1/4 chance of getting the third, - * and a 1/4 chance of getting the fourth. - * - * And now a proof by induction: - * it works for 1 intrinsic (1 in 1 of getting it) - * for 2 you have a 1 in 2 chance of getting the second, - * otherwise you keep the first - * for 3 you have a 1 in 3 chance of getting the third, - * otherwise you keep the first or the second - * for n+1 you have a 1 in n+1 chance of getting the (n+1)st, - * otherwise you keep the previous one. - * Elliott Kleinrock, October 5, 1990 + * Strength from giants is now treated like an intrinsic + * rather than being given unconditionally. */ - - count = 0; /* number of possible intrinsics */ - tmp = 0; /* which one we will try to give */ - for (i = 1; i <= LAST_PROP; i++) { - if (intrinsic_possible(i, ptr)) { - count++; - /* a 1 in count chance of replacing the old - * one with this one, and a count-1 in count - * chance of keeping the old one. (note - * that 1 in 1 and 0 in 1 are what we want - * for the first one - */ - if (!rn2(count)) { + count = 0; /* number of possible intrinsics */ + tmp = 0; /* which one we will try to give */ + if (conveys_STR) { + count = 1; + tmp = -1; /* use -1 as fake prop index for STR */ #ifdef DEBUG - debugpline("Intrinsic %d replacing %d", - i, tmp); + debugpline("\"Intrinsic\" strength, %d", tmp); #endif - tmp = i; - } - } - } - - /* if any found try to give them one */ - if (count) givit(tmp, ptr); + } + for (i = 1; i <= LAST_PROP; i++) { + if (!intrinsic_possible(i, ptr)) continue; + ++count; + /* a 1 in count chance of replacing the old choice + with this one, and a count-1 in count chance + of keeping the old choice (note that 1 in 1 and + 0 in 1 are what we want for the first candidate) */ + if (!rn2(count)) { +#ifdef DEBUG + debugpline("Intrinsic %d replacing %d", i, tmp); +#endif + tmp = i; + } + } + /* if strength is the only candidate, give it 50% chance */ + if (conveys_STR && count == 1 && !rn2(2)) tmp = 0; + /* if something was chosen, give it now (givit() might fail) */ + if (tmp == -1) + gainstr((struct obj *)0, 0, TRUE); + else if (tmp > 0) + givit(tmp, ptr); } break; } @@ -1413,7 +1390,7 @@ const char *mesg; if (!tin->cursed) pline("This makes you feel like %s!", Hallucination ? "Swee'pea" : "Popeye"); - gainstr(tin, 0); + gainstr(tin, 0, FALSE); costly_tin(COST_OPEN); @@ -2087,7 +2064,7 @@ register struct obj *otmp; break; case LUMP_OF_ROYAL_JELLY: /* This stuff seems to be VERY healthy! */ - gainstr(otmp, 1); + gainstr(otmp, 1, TRUE); if (Upolyd) { u.mh += otmp->cursed ? -rnd(20) : rnd(20); if (u.mh > u.mhmax) {