Potions of Poison and Sickness 0.5 for NetHack 3.4.3 Author: Justin T Nelson Redefines the potion of sickness and adds a new potion type The idea behind this is to distinguish "biologically contaminated" fruit juice -- a bacterial or fungal infection -- from "poison", meaning arsenic, venom, et cetera ("Yecch! This stuff tastes like poison."). The former doesn't go on your arrows, and the latter doesn't heal Pestilence. * Potion of sickness renamed to "poison", and has 10% instakill vs. monsters. * Otherwise does a bit of damage, based on die roll rather than maxHP. * New "potion of sickness" causes illness like a tainted corpse. * Sickness potion does maxHP-based damage to monsters, or heals Pestilence. * Diluted sickness does half damage. * All undead and F are immune to sickness. * Both potions can be turned to juice by dipping a unicorn horn. Issues: * Your gravestone still says "poisoned by a rotted giant corpse", "poisoned by Pestilence", or "poisoned by a contaminated potion" [of sickness], though it is in fact death by sickness. * "contaminated" water from fountains should be reclassified. * "FoodPois" label may need rethinking. diff -Nurd src-orig/apply.c src/apply.c --- src-orig/apply.c 2003-12-07 17:39:14.000000000 -0600 +++ src/apply.c 2007-10-02 13:44:14.890625000 -0500 @@ -2965,7 +2965,8 @@ otmp = mkobj(POTION_CLASS, FALSE); if (objects[otmp->otyp].oc_magic) do { otmp->otyp = rnd_class(POT_BOOZE, POT_WATER); - } while (otmp->otyp == POT_SICKNESS); + } while (otmp->otyp == POT_POISON + || otmp->otyp == POT_SICKNESS); what = "A potion"; } else { otmp = mkobj(FOOD_CLASS, FALSE); diff -Nurd src-orig/objects.c src/objects.c --- src-orig/objects.c 2003-12-07 17:39:14.000000000 -0600 +++ src/objects.c 2007-09-30 21:27:12.906250000 -0500 @@ -744,7 +744,8 @@ POTION("full healing", "black", 1, 0, 10, 200, CLR_BLACK), POTION("polymorph", "golden", 1, 0, 10, 200, CLR_YELLOW), POTION("booze", "brown", 0, 0, 42, 50, CLR_BROWN), -POTION("sickness", "fizzy", 0, 0, 42, 50, CLR_CYAN), +POTION("poison", "fizzy", 0, 0, 32, 50, CLR_CYAN), +POTION("sickness", "hazy", 0, 0, 10, 50, CLR_MAGENTA), POTION("fruit juice", "dark", 0, 0, 42, 50, CLR_BLACK), POTION("acid", "white", 0, 0, 10, 250, CLR_WHITE), POTION("oil", "murky", 0, 0, 30, 250, CLR_BROWN), diff -Nurd src-orig/potion.c src/potion.c --- src-orig/potion.c 2003-12-07 17:39:14.000000000 -0600 +++ src/potion.c 2007-10-02 14:14:56.718750000 -0500 @@ -652,20 +652,20 @@ return(1); /* nothing detected */ exercise(A_WIS, TRUE); break; - case POT_SICKNESS: + case POT_POISON: pline("Yecch! This stuff tastes like poison."); + char killerbuf[64]; + sprintf(killerbuf, "poisoned %s", + (otmp->fromsink) ? "tap water" : fruitname(TRUE)); if (otmp->blessed) { pline("(But in fact it was mildly stale %s.)", fruitname(TRUE)); - if (!Role_if(PM_HEALER)) { - /* NB: blessed otmp->fromsink is not possible */ - losehp(1, "mildly contaminated potion", KILLED_BY_AN); - } + if (!Poison_resistance) + losehp(1, killerbuf, KILLED_BY); } else { - if(Poison_resistance) - pline( - "(But in fact it was biologically contaminated %s.)", - fruitname(TRUE)); + if(Poison_resistance && !Role_if(PM_HEALER)) + You("are only slightly affected by the poisoned %s.", + fruitname(TRUE)); if (Role_if(PM_HEALER)) pline("Fortunately, you have been immunized."); else { @@ -677,14 +677,9 @@ Poison_resistance ? -1 : -rn1(4,3), TRUE); } - if(!Poison_resistance) { - if (otmp->fromsink) - losehp(rnd(10)+5*!!(otmp->cursed), - "contaminated tap water", KILLED_BY); - else - losehp(rnd(10)+5*!!(otmp->cursed), - "contaminated potion", KILLED_BY_AN); - } + if(!Poison_resistance) + losehp(rnd(10)+5*!!(otmp->cursed), + killerbuf, KILLED_BY); exercise(A_CON, FALSE); } } @@ -693,6 +688,23 @@ (void) make_hallucinated(0L,FALSE,0L); } break; + case POT_SICKNESS: + pline("Ulch - that %s was tainted!", + (otmp->fromsink) ? "water" : fruitname(TRUE)); + if(Sick_resistance) { + pline_The("biologically contaminated %s doesn't make you sick.", + (otmp->fromsink) ? "water" : "juice"); + break; + } + long sick_time; + sprintf(killerbuf, "contaminated %s", + (otmp->fromsink) ? "sink" : "potion"); + make_sick(Sick ? 1L : + (otmp->blessed) ? 20L : + (otmp->cursed) ? 10L : + (long) rn1(10, 10), + killerbuf, TRUE, SICK_VOMITABLE); + break; case POT_CONFUSION: if(!Confusion) if (Hallucination) { @@ -1016,40 +1028,74 @@ } else { boolean angermon = TRUE; + /* GOTOs? We don't need no stinking GOTOs. */ + short tmp_otyp = obj->otyp; + if (mon->data == &mons[PM_PESTILENCE]) { + if (obj->otyp == POT_HEALING || + obj->otyp == POT_EXTRA_HEALING || + obj->otyp == POT_FULL_HEALING) + tmp_otyp = POT_SICKNESS; + else if (obj->otyp == POT_SICKNESS) + tmp_otyp = POT_FULL_HEALING; + } if (!your_fault) angermon = FALSE; - switch (obj->otyp) { + switch (tmp_otyp) { case POT_HEALING: case POT_EXTRA_HEALING: case POT_FULL_HEALING: - if (mon->data == &mons[PM_PESTILENCE]) goto do_illness; - /*FALLTHRU*/ case POT_RESTORE_ABILITY: case POT_GAIN_ABILITY: - do_healing: angermon = FALSE; if(mon->mhp < mon->mhpmax) { mon->mhp = mon->mhpmax; if (canseemon(mon)) pline("%s looks sound and hale again.", Monnam(mon)); } + case POT_POISON: + if (resists_poison(mon)) { + if (canseemon(mon)) + pline("%s looks unharmed.", Monnam(mon)); + break; + } + /* Poisoned arrows cut the monster and introduce a small + * amount of poison into the body. The broken flask is also + * likely to cut, and there's a lot more poison. Thus we + * will keep the 10% instakill. Damage is no longer based + * on mhpmax; poison should be potentially lethal. + */ + if(!rn2(10) && !resist(mon, POTION_CLASS, 0, NOTELL)) { + if (canseemon(mon)) { + if (humanoid(mon->data) && !breathless(mon->data)) + pline("%s gasps and clutches %s chest!", + Monnam(mon), mhis(mon)); + else pline("%s drops dead!", Monnam(mon)); + } + killed(mon); + break; + } + int pain = d((resist(mon, POTION_CLASS, 0, NOTELL) ? 2:4),10); + mon->mhp -= pain; + mon->mhpmax -= pain / 2; + if (canseemon(mon)) + pline("%s looks rather ill.", Monnam(mon)); + if (mon->mhp < 1) killed(mon); break; case POT_SICKNESS: - if (mon->data == &mons[PM_PESTILENCE]) goto do_healing; - if (dmgtype(mon->data, AD_DISE) || - dmgtype(mon->data, AD_PEST) || /* won't happen, see prior goto */ - resists_poison(mon)) { + if ((dmgtype(mon->data, AD_DISE) || + mon->data->mlet == S_FUNGUS || + is_undead(mon->data)) && + obj->otyp == POT_SICKNESS) { /* healing vs Pesty still hurts */ if (canseemon(mon)) pline("%s looks unharmed.", Monnam(mon)); break; } - do_illness: - if((mon->mhpmax > 3) && !resist(mon, POTION_CLASS, 0, NOTELL)) - mon->mhpmax /= 2; - if((mon->mhp > 2) && !resist(mon, POTION_CLASS, 0, NOTELL)) - mon->mhp /= 2; - if (mon->mhp > mon->mhpmax) mon->mhp = mon->mhpmax; + pain = mon->mhpmax * ((obj->oeroded) ? 1 : 2) + / (resist(mon, POTION_CLASS, 0, NOTELL) ? 6 : 3); + mon->mhp -= pain; + mon->mhpmax -= pain / 2; if (canseemon(mon)) - pline("%s looks rather ill.", Monnam(mon)); + pline("%s looks very ill!", Monnam(mon)); + if (mon->mhp < 1) killed(mon); break; case POT_CONFUSION: case POT_BOOZE: @@ -1223,7 +1269,7 @@ if (u.uhp < u.uhpmax) u.uhp++, flags.botl = 1; exercise(A_CON, TRUE); break; - case POT_SICKNESS: + case POT_POISON: if (!Role_if(PM_HEALER)) { if (Upolyd) { if (u.mh <= 5) u.mh = 1; else u.mh -= 5; @@ -1234,6 +1280,9 @@ exercise(A_CON, FALSE); } break; + case POT_SICKNESS: + if (!Role_if(PM_HEALER)) exercise(A_CON, FALSE); + break; case POT_HALLUCINATION: You("have a momentary vision."); break; @@ -1359,6 +1408,7 @@ } case UNICORN_HORN: switch (o2->otyp) { + case POT_POISON: case POT_SICKNESS: return POT_FRUIT_JUICE; case POT_HALLUCINATION: @@ -1390,6 +1440,8 @@ break; case POT_FRUIT_JUICE: switch (o2->otyp) { + case POT_POISON: + return POT_POISON; case POT_SICKNESS: return POT_SICKNESS; case POT_SPEED: @@ -1689,7 +1741,7 @@ break; case 2: case 3: - obj->otyp = POT_SICKNESS; + obj->otyp = POT_POISON; break; case 4: { @@ -1745,7 +1797,7 @@ #endif if(is_poisonable(obj)) { - if(potion->otyp == POT_SICKNESS && !obj->opoisoned) { + if(potion->otyp == POT_POISON && !obj->opoisoned) { char buf[BUFSZ]; if (potion->quan > 1L) Sprintf(buf, "One of %s", the(xname(potion))); diff -Nurd src-orig/u_init.c src/u_init.c --- src-orig/u_init.c 2003-12-07 17:39:14.000000000 -0600 +++ src/u_init.c 2007-09-30 18:22:02.593750000 -0500 @@ -123,7 +123,7 @@ { SHORT_SWORD, 0, WEAPON_CLASS, 1, UNDEF_BLESS }, { DAGGER, 0, WEAPON_CLASS, 10, 0 }, /* quan is variable */ { LEATHER_ARMOR, 1, ARMOR_CLASS, 1, UNDEF_BLESS }, - { POT_SICKNESS, 0, POTION_CLASS, 1, 0 }, + { POT_POISON, 0, POTION_CLASS, 1, 0 }, { LOCK_PICK, 9, TOOL_CLASS, 1, 0 }, { SACK, 0, TOOL_CLASS, 1, 0 }, { 0, 0, 0, 0, 0 } diff -Nurd src-orig/zap.c src/zap.c --- src-orig/zap.c 2003-12-07 17:39:14.000000000 -0600 +++ src/zap.c 2007-10-02 14:02:27.765625000 -0500 @@ -886,6 +886,8 @@ /* sickness is "biologically contaminated" fruit juice; cancel it * and it just becomes fruit juice... whereas see invisible * tastes like "enchanted" fruit juice, it similarly cancels. + * -- Poison is juice too, but as a poison coating does not cancel + * from weapons, the potion doesn't cancel either. --Nelson */ obj->otyp = POT_FRUIT_JUICE; } else {