diff -rup source-orig\include\obj.h source-main\include\obj.h --- source-orig\include\obj.h Sun Dec 07 17:39:13 2003 +++ source-main\include\obj.h Thu Dec 03 17:02:10 2009 @@ -70,6 +70,7 @@ struct obj { #define orotten oeroded /* rotten food */ #define odiluted oeroded /* diluted potions */ #define norevive oeroded2 +#define orefilled oeroded2 /* refilled potions */ Bitfield(oerodeproof,1); /* erodeproof weapon/armor */ Bitfield(olocked,1); /* object is locked */ Bitfield(obroken,1); /* lock has been broken */ diff -rup source-orig\src\detect.c source-main\src\detect.c --- source-orig\src\detect.c Sun Dec 07 17:39:13 2003 +++ source-main\src\detect.c Sat Dec 05 14:47:52 2009 @@ -434,8 +434,10 @@ int class; /* an object class, 0 for a Strcpy(stuff, class ? oclass_names[class] : "objects"); if (boulder && class != ROCK_CLASS) Strcat(stuff, " and/or large stones"); - if (do_dknown) for(obj = invent; obj; obj = obj->nobj) do_dknown_of(obj); + if(!(detector->oclass == POTION_CLASS && detector->orefilled && !detector->cursed)) + if (do_dknown) for(obj = invent; obj; obj = obj->nobj) do_dknown_of(obj); + if(!(detector->oclass == POTION_CLASS && detector->orefilled && detector->cursed)) for (obj = fobj; obj; obj = obj->nobj) { if ((!class && !boulder) || o_in(obj, class) || o_in(obj, boulder)) { if (obj->ox == u.ux && obj->oy == u.uy) ctu++; @@ -444,31 +446,33 @@ int class; /* an object class, 0 for a if (do_dknown) do_dknown_of(obj); } - for (obj = level.buriedobjlist; obj; obj = obj->nobj) { - if (!class || o_in(obj, class)) { - if (obj->ox == u.ux && obj->oy == u.uy) ctu++; - else ct++; - } - if (do_dknown) do_dknown_of(obj); - } + if(!(detector->oclass == POTION_CLASS && detector->orefilled)) { + for (obj = level.buriedobjlist; obj; obj = obj->nobj) { + if (!class || o_in(obj, class)) { + if (obj->ox == u.ux && obj->oy == u.uy) ctu++; + else ct++; + } + if (do_dknown) do_dknown_of(obj); + } - for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { - if (DEADMONSTER(mtmp)) continue; - for (obj = mtmp->minvent; obj; obj = obj->nobj) { - if ((!class && !boulder) || o_in(obj, class) || o_in(obj, boulder)) ct++; - if (do_dknown) do_dknown_of(obj); - } - if ((is_cursed && mtmp->m_ap_type == M_AP_OBJECT && - (!class || class == objects[mtmp->mappearance].oc_class)) || + for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { + if (DEADMONSTER(mtmp)) continue; + for (obj = mtmp->minvent; obj; obj = obj->nobj) { + if ((!class && !boulder) || o_in(obj, class) || o_in(obj, boulder)) ct++; + if (do_dknown) do_dknown_of(obj); + } + if ((is_cursed && mtmp->m_ap_type == M_AP_OBJECT && + (!class || class == objects[mtmp->mappearance].oc_class)) || #ifndef GOLDOBJ - (mtmp->mgold && (!class || class == COIN_CLASS))) { + (mtmp->mgold && (!class || class == COIN_CLASS))) { #else - (findgold(mtmp->minvent) && (!class || class == COIN_CLASS))) { + (findgold(mtmp->minvent) && (!class || class == COIN_CLASS))) { #endif - ct++; - break; + ct++; + break; + } + } } - } if (!clear_stale_map(!class ? ALL_CLASSES : class, 0) && !ct) { if (!ctu) { diff -rup source-orig\src\muse.c source-main\src\muse.c --- source-orig\src\muse.c Sun Dec 07 17:39:13 2003 +++ source-main\src\muse.c Sat Dec 05 23:45:17 2009 @@ -31,6 +31,7 @@ STATIC_DCL void FDECL(mbhit, STATIC_DCL void FDECL(you_aggravate, (struct monst *)); STATIC_DCL void FDECL(mon_consume_unstone, (struct monst *,struct obj *, BOOLEAN_P,BOOLEAN_P)); +STATIC_DCL void FDECL(m_leavebottle, (struct monst *)); static struct musable { struct obj *offensive; @@ -77,6 +78,7 @@ struct obj *obj; if (!enexto(&cc, mon->mx, mon->my, &mons[PM_GHOST])) return 0; mquaffmsg(mon, obj); m_useup(mon, obj); + m_leavebottle(mon); mtmp = makemon(&mons[PM_GHOST], cc.x, cc.y, NO_MM_FLAGS); if (!mtmp) { if (vis) pline(empty); @@ -100,6 +102,7 @@ struct obj *obj; if (!enexto(&cc, mon->mx, mon->my, &mons[PM_DJINNI])) return 0; mquaffmsg(mon, obj); m_useup(mon, obj); + m_leavebottle(mon); mtmp = makemon(&mons[PM_DJINNI], cc.x, cc.y, NO_MM_FLAGS); if (!mtmp) { if (vis) pline(empty); @@ -846,7 +849,11 @@ mon_tele: mquaffmsg(mtmp, otmp); i = d(6 + 2 * bcsign(otmp), 4); mtmp->mhp += i; - if (mtmp->mhp > mtmp->mhpmax) mtmp->mhp = ++mtmp->mhpmax; + if (mtmp->mhp > mtmp->mhpmax) { + if(!otmp->orefilled) + mtmp->mhpmax++; + mtmp->mhp = mtmp->mhpmax; + } if (!otmp->cursed && !mtmp->mcansee) { mtmp->mcansee = 1; mtmp->mblinded = 0; @@ -855,13 +862,17 @@ mon_tele: if (vismon) pline("%s looks better.", Monnam(mtmp)); if (oseen) makeknown(POT_HEALING); m_useup(mtmp, otmp); + m_leavebottle(mtmp); return 2; case MUSE_POT_EXTRA_HEALING: mquaffmsg(mtmp, otmp); i = d(6 + 2 * bcsign(otmp), 8); mtmp->mhp += i; - if (mtmp->mhp > mtmp->mhpmax) - mtmp->mhp = (mtmp->mhpmax += (otmp->blessed ? 5 : 2)); + if (mtmp->mhp > mtmp->mhpmax) { + if(!otmp->orefilled) + mtmp->mhpmax += (otmp->blessed ? 5 : 2); + mtmp->mhp = mtmp->mhpmax; + } if (!mtmp->mcansee) { mtmp->mcansee = 1; mtmp->mblinded = 0; @@ -870,11 +881,14 @@ mon_tele: if (vismon) pline("%s looks much better.", Monnam(mtmp)); if (oseen) makeknown(POT_EXTRA_HEALING); m_useup(mtmp, otmp); + m_leavebottle(mtmp); return 2; case MUSE_POT_FULL_HEALING: mquaffmsg(mtmp, otmp); if (otmp->otyp == POT_SICKNESS) unbless(otmp); /* Pestilence */ - mtmp->mhp = (mtmp->mhpmax += (otmp->blessed ? 8 : 4)); + if(!otmp->orefilled) + mtmp->mhpmax += (otmp->blessed ? 8 : 4); + mtmp->mhp = mtmp->mhpmax; if (!mtmp->mcansee && otmp->otyp != POT_SICKNESS) { mtmp->mcansee = 1; mtmp->mblinded = 0; @@ -883,6 +897,7 @@ mon_tele: if (vismon) pline("%s looks completely healed.", Monnam(mtmp)); if (oseen) makeknown(otmp->otyp); m_useup(mtmp, otmp); + m_leavebottle(mtmp); return 2; case MUSE_LIZARD_CORPSE: /* not actually called for its unstoning effect */ @@ -1723,6 +1738,7 @@ struct monst *mtmp; docall(otmp); } m_useup(mtmp, otmp); + m_leavebottle(mtmp); migrate_to_level(mtmp, ledger_no(&tolevel), MIGR_RANDOM, (coord *)0); return 2; @@ -1735,14 +1751,24 @@ skipmsg: docall(otmp); } m_useup(mtmp, otmp); + m_leavebottle(mtmp); return 2; } } if (vismon) pline("%s seems more experienced.", Monnam(mtmp)); if (oseen) makeknown(POT_GAIN_LEVEL); m_useup(mtmp, otmp); - if (!grow_up(mtmp,(struct monst *)0)) return 1; - /* grew into genocided monster */ + m_leavebottle(mtmp); + { + int mhpmax = mtmp->mhpmax; + int mhp = mtmp->mhp; + if (!grow_up(mtmp,(struct monst *)0)) return 1; + /* grew into genocided monster */ + if(otmp->orefilled) { // Refilled potions don't increase max HP + mtmp->mhpmax = mhpmax; + mtmp->mhp = mhp; + } + } return 2; case MUSE_WAN_MAKE_INVISIBLE: case MUSE_POT_INVISIBILITY: @@ -1766,6 +1792,7 @@ skipmsg: if (otmp->otyp == POT_INVISIBILITY) { if (otmp->cursed) you_aggravate(mtmp); m_useup(mtmp, otmp); + m_leavebottle(mtmp); } return 2; case MUSE_WAN_SPEED_MONSTER: @@ -1779,8 +1806,13 @@ skipmsg: different methods of maintaining speed ratings: player's character becomes "very fast" temporarily; monster becomes "one stage faster" permanently */ - mon_adjust_speed(mtmp, 1, otmp); + if(!otmp->orefilled) + mon_adjust_speed(mtmp, 1, otmp); + else + mtmp->movement += (NORMAL_SPEED * 2 * (2 + bcsign(otmp))) + / (otmp->odiluted ? 4 : 3); m_useup(mtmp, otmp); + m_leavebottle(mtmp); return 2; case MUSE_WAN_POLYMORPH: mzapmsg(mtmp, otmp, TRUE); @@ -1794,6 +1826,7 @@ skipmsg: (void) newcham(mtmp, muse_newcham_mon(mtmp), FALSE, FALSE); if (oseen) makeknown(POT_POLYMORPH); m_useup(mtmp, otmp); + m_leavebottle(mtmp); return 2; case MUSE_POLY_TRAP: if (vismon) @@ -2145,6 +2178,7 @@ boolean stoning; } else if (flags.soundok) You_hear("%s.", (obj->otyp == POT_ACID) ? "drinking" : "chewing"); m_useup(mon, obj); + m_leavebottle(mon); if (((obj->otyp == POT_ACID) || acidic(&mons[obj->corpsenm])) && !resists_acid(mon)) { mon->mhp -= rnd(15); @@ -2177,6 +2211,19 @@ boolean stoning; mon->mconf = 0; } mon->mlstmv = monstermoves; /* it takes a turn */ +} + +void +m_leavebottle(mon) +register struct monst *mon; +{ + register struct obj *new_obj; + if(rn2(3)) { + new_obj = mksobj(POT_NOTHING, FALSE, FALSE); + new_obj->orefilled = 1; + obj_extract_self(new_obj); + add_to_minv(mon, new_obj); + } } /*muse.c*/ diff -rup source-orig\src\o_init.c source-main\src\o_init.c --- source-orig\src\o_init.c Sun Dec 07 17:39:13 2003 +++ source-main\src\o_init.c Thu Dec 03 19:54:03 2009 @@ -195,7 +195,7 @@ shuffle_all() int j = last-1; if (oclass == POTION_CLASS) - j -= 1; /* only water has a fixed description */ + j -= 2; /* only water and empty bottle have fixed descriptions */ else if (oclass == AMULET_CLASS || oclass == SCROLL_CLASS || oclass == SPBOOK_CLASS) { diff -rup source-orig\src\objects.c source-main\src\objects.c --- source-orig\src\objects.c Sun Dec 07 17:39:13 2003 +++ source-main\src\objects.c Thu Dec 03 18:40:31 2009 @@ -749,6 +749,7 @@ POTION("fruit juice", "dark", POTION("acid", "white", 0, 0, 10, 250, CLR_WHITE), POTION("oil", "murky", 0, 0, 30, 250, CLR_BROWN), POTION("water", "clear", 0, 0, 92, 100, CLR_CYAN), +POTION("nothing", "empty", 0, 0, 0, 1, CLR_CYAN), // Currently causes problems with graphics, may break savefiles #undef POTION /* scrolls ... */ diff -rup source-orig\src\objnam.c source-main\src\objnam.c --- source-orig\src\objnam.c Sun Dec 07 17:39:13 2003 +++ source-main\src\objnam.c Sat Dec 05 14:13:03 2009 @@ -383,6 +383,10 @@ register struct obj *obj; case POTION_CLASS: if (obj->dknown && obj->odiluted) Strcpy(buf, "diluted "); + if (obj->dknown && obj->orefilled && obj->otyp != POT_NOTHING) + Strcat(buf, "refilled "); + if (obj->dknown && obj->otyp == POT_NOTHING && !obj->orefilled) + Strcat(buf, "fresh "); if(nn || un || !obj->dknown) { Strcat(buf, "potion"); if(!obj->dknown) break; @@ -528,7 +532,7 @@ char *prefix; if (!is_damageable(obj) && !iscrys) return; /* The only cases where any of these bits do double duty are for - * rotted food and diluted potions, which are all not is_damageable(). + * rotted food and diluted/refilled potions, which are all not is_damageable(). */ if (obj->oeroded && !iscrys) { switch (obj->oeroded) { @@ -1762,7 +1766,7 @@ boolean from_user; int isinvisible; #endif int halfeaten, mntmp, contents; - int islit, unlabeled, ishistoric, isdiluted; + int islit, unlabeled, ishistoric, isdiluted, isrefilled; struct fruit *f; int ftype = current_fruit; char fruitbuf[BUFSZ]; @@ -1791,7 +1795,8 @@ boolean from_user; isinvisible = #endif ispoisoned = isgreased = eroded = eroded2 = erodeproof = - halfeaten = islit = unlabeled = ishistoric = isdiluted = 0; + halfeaten = islit = unlabeled = ishistoric = isdiluted = + isrefilled = 0; mntmp = NON_PM; #define UNDEFINED 0 #define EMPTY 1 @@ -1889,6 +1894,8 @@ boolean from_user; ishistoric = 1; } else if (!strncmpi(bp, "diluted ", l=8)) { isdiluted = 1; + } else if (!strncmpi(bp, "refilled ", l=9)) { + isrefilled = 1; } else if(!strncmpi(bp, "empty ", l=6)) { contents = EMPTY; } else break; @@ -2673,6 +2680,9 @@ typfnd: if (isdiluted && otmp->oclass == POTION_CLASS && otmp->otyp != POT_WATER) otmp->odiluted = 1; + if ((isrefilled && otmp->oclass == POTION_CLASS) || + otmp->otyp == POT_NOTHING) + otmp->orefilled = 1; if (name) { const char *aname; diff -rup source-orig\src\potion.c source-main\src\potion.c --- source-orig\src\potion.c Sun Dec 07 17:39:13 2003 +++ source-main\src\potion.c Sat Dec 05 23:25:26 2009 @@ -13,6 +13,7 @@ static NEARDATA const char beverages[] = STATIC_DCL long FDECL(itimeout, (long)); STATIC_DCL long FDECL(itimeout_incr, (long,int)); STATIC_DCL void NDECL(ghost_from_bottle); +STATIC_DCL void NDECL(leavebottle); STATIC_DCL short FDECL(mixtype, (struct obj *,struct obj *)); /* force `val' to be within valid range for intrinsic timeout value */ @@ -320,6 +321,29 @@ ghost_from_bottle() nomovemsg = "You regain your composure."; } +void +reinventory(obj) +register struct obj *obj; +{ + obj_extract_self(obj); + obj = hold_another_object(obj, + "You juggle and drop %s!", + doname(obj), (const char *)0); +} + +void +leavebottle() +{ + register struct obj *new_obj; + if(rnl(10) < rnd(15)) { + new_obj = mksobj(POT_NOTHING, FALSE, FALSE); + new_obj->orefilled = 1; + reinventory(new_obj); + } else { + pline_The("bottle cracks in your grip."); + } +} + /* "Quaffing is like drinking, except you spill more." -- Terry Pratchett */ int @@ -367,15 +391,17 @@ dodrink() if (potion_descr) { if (!strcmp(potion_descr, "milky") && flags.ghost_count < MAXMONNO && - !rn2(POTION_OCCUPANT_CHANCE(flags.ghost_count))) { + !rn2(POTION_OCCUPANT_CHANCE(flags.ghost_count + (otmp->orefilled ? 25 : 0)))) { ghost_from_bottle(); useup(otmp); + leavebottle(); return(1); } else if (!strcmp(potion_descr, "smoky") && flags.djinni_count < MAXMONNO && - !rn2(POTION_OCCUPANT_CHANCE(flags.djinni_count))) { + !rn2(POTION_OCCUPANT_CHANCE(flags.djinni_count + (otmp->orefilled ? 25 : 0)))) { djinni_from_bottle(otmp); useup(otmp); + leavebottle(); return(1); } } @@ -405,6 +431,7 @@ register struct obj *otmp; docall(otmp); } useup(otmp); + leavebottle(); return(1); } @@ -416,6 +443,38 @@ peffects(otmp) switch(otmp->otyp){ case POT_RESTORE_ABILITY: + if(otmp->orefilled) { + if(otmp->cursed) { + if (HFast & INTRINSIC) { + HFast &= ~INTRINSIC; + You("feel your speed return to normal."); + } else { + You("feel normal."); + } + } else if(otmp->blessed) { + if(!Stoned && !HStun) { + You("feel mobile."); + } + if(Stoned) { + Stoned = 5; + You("loosen up slightly."); + } + if(HStun) { + make_stunned(0L, TRUE); + } + } else { + if(Wounded_legs +#ifdef STEED + && !u.usteed /* heal_legs() would heal steeds legs */ +#endif + ) + heal_legs(); + else + Your("legs feel rested"); + } + break; + } + /* else fall through to next case */ case SPE_RESTORE_ABILITY: unkn++; if(otmp->cursed) { @@ -448,8 +507,12 @@ peffects(otmp) break; case POT_WATER: if(!otmp->blessed && !otmp->cursed) { - pline("This tastes like water."); - u.uhunger += rnd(10); + pline("This tastes like water."); + if(!otmp->orefilled) { + u.uhunger += rnd(10); + } else { + u.uhunger += rnd(2); + } newuhs(FALSE); break; } @@ -503,7 +566,7 @@ peffects(otmp) make_confused(itimeout_incr(HConfusion, d(3,8)), FALSE); /* the whiskey makes us feel better */ if (!otmp->odiluted) healup(1, 0, FALSE, FALSE); - u.uhunger += 10 * (2 + bcsign(otmp)); + if (!otmp->orefilled) u.uhunger += 10 * (2 + bcsign(otmp)); newuhs(FALSE); exercise(A_WIS, FALSE); if(otmp->cursed) { @@ -522,10 +585,19 @@ peffects(otmp) (void) adjattrib(A_INT, 1, FALSE); (void) adjattrib(A_WIS, 1, FALSE); } - You_feel("self-knowledgeable..."); - display_nhwindow(WIN_MESSAGE, FALSE); - enlightenment(0); - pline_The("feeling subsides."); + if(!otmp->orefilled) { + You_feel("self-knowledgeable..."); + display_nhwindow(WIN_MESSAGE, FALSE); + enlightenment(0); + pline_The("feeling subsides."); + } else { + if (!BClairvoyant) + do_vicinity_map(); + /* at present, only one thing blocks clairvoyance */ + else if (uarmh && uarmh->otyp == CORNUTHAUM) + You("sense a pointy hat on top of your %s.", + body_part(HEAD)); + } exercise(A_WIS, TRUE); } break; @@ -542,12 +614,22 @@ peffects(otmp) } else { self_invis_message(); } - if (otmp->blessed) HInvis |= FROMOUTSIDE; - else incr_itimeout(&HInvis, rn1(15,31)); - newsym(u.ux,u.uy); /* update position */ - if(otmp->cursed) { - pline("For some reason, you feel your presence is known."); - aggravate(); + if(!otmp->orefilled) { + if (otmp->blessed) HInvis |= FROMOUTSIDE; + else incr_itimeout(&HInvis, rn1(15,31)); + newsym(u.ux,u.uy); /* update position */ + if(otmp->cursed) { + pline("For some reason, you feel your presence is known."); + aggravate(); + } + } else { + if(otmp->blessed) + incr_itimeout(&HInvis, rn1(15,31)); + else if(otmp->cursed) + incr_itimeout(&HInvis, rn1(1,15)); + else + incr_itimeout(&HInvis, rn1(1,31)); + newsym(u.ux,u.uy); /* update position */ } break; case POT_SEE_INVISIBLE: @@ -567,20 +649,29 @@ peffects(otmp) otmp->odiluted ? "reconstituted " : "", fruitname(TRUE)); if (otmp->otyp == POT_FRUIT_JUICE) { - u.uhunger += (otmp->odiluted ? 5 : 10) * (2 + bcsign(otmp)); + u.uhunger += (otmp->odiluted ? 1 : 2) * (otmp->orefilled ? 2 : 5) * (2 + bcsign(otmp)); newuhs(FALSE); break; } - if (!otmp->cursed) { - /* Tell them they can see again immediately, which - * will help them identify the potion... - */ - make_blinded(0L,TRUE); + if(!otmp->orefilled) { + if (!otmp->cursed) { + /* Tell them they can see again immediately, which + * will help them identify the potion... + */ + make_blinded(0L,TRUE); + } + if (otmp->blessed) + HSee_invisible |= FROMOUTSIDE; + else + incr_itimeout(&HSee_invisible, rn1(100,750)); + } else { + if(otmp->blessed) + incr_itimeout(&HSee_invisible, rn1(100,750)); + else if(otmp->cursed) + incr_itimeout(&HSee_invisible, rn1(1,100)); + else + incr_itimeout(&HSee_invisible, rn1(1,750)); } - if (otmp->blessed) - HSee_invisible |= FROMOUTSIDE; - else - incr_itimeout(&HSee_invisible, rn1(100,750)); set_mimic_blocking(); /* do special mimic handling */ see_monsters(); /* see invisible monsters */ newsym(u.ux,u.uy); /* see yourself! */ @@ -603,7 +694,7 @@ peffects(otmp) else Your("%s are frozen to the %s!", makeplural(body_part(FOOT)), surface(u.ux, u.uy)); - nomul(-(rn1(10, 25 - 12*bcsign(otmp)))); + nomul(-(rn1(10, (otmp->orefilled ? 12 : 25) - 12*bcsign(otmp)))); nomovemsg = You_can_move_again; exercise(A_DEX, FALSE); } @@ -613,7 +704,7 @@ peffects(otmp) You("yawn."); else { You("suddenly fall asleep!"); - fall_asleep(-rn1(10, 25 - 12*bcsign(otmp)), TRUE); + fall_asleep(-rn1(10, (otmp->orefilled ? 12 : 25) - 12*bcsign(otmp)), TRUE); } break; case POT_MONSTER_DETECTION: @@ -625,9 +716,11 @@ peffects(otmp) unkn++; /* after a while, repeated uses become less effective */ if (HDetect_monsters >= 300L) - i = 1; - else - i = rn1(40,21); + i = 1; + else if(!otmp->orefilled) + i = rn1(40,21); + else + i = rn1(10,5); incr_itimeout(&HDetect_monsters, i); for (x = 1; x < COLNO; x++) { for (y = 0; y < ROWNO; y++) { @@ -674,7 +767,7 @@ peffects(otmp) if (!Fixed_abil) { poisontell(typ); (void) adjattrib(typ, - Poison_resistance ? -1 : -rn1(4,3), + Poison_resistance ? -1 : -(otmp->orefilled ? rn1(2,1) : rn1(4,3)), TRUE); } if(!Poison_resistance) { @@ -682,13 +775,13 @@ peffects(otmp) losehp(rnd(10)+5*!!(otmp->cursed), "contaminated tap water", KILLED_BY); else - losehp(rnd(10)+5*!!(otmp->cursed), + losehp(rnd(10)+(otmp->orefilled ? 0 : 5)*!!(otmp->cursed), "contaminated potion", KILLED_BY_AN); } exercise(A_CON, FALSE); } } - if(Hallucination) { + if(Hallucination && !otmp->orefilled) { You("are shocked back to your senses!"); (void) make_hallucinated(0L,FALSE,0L); } @@ -711,6 +804,10 @@ peffects(otmp) unkn++; } else if (Fixed_abil) { nothing++; + } else if(otmp->orefilled) { + adjattrib(A_STR, 1, 0); + if(otmp->blessed) + adjattrib(A_DEX, 1, 0); } else { /* If blessed, increase all; if not, try up to */ int itmp; /* 6 times to find one which can be increased. */ i = -1; /* increment to 0 */ @@ -725,6 +822,33 @@ peffects(otmp) } break; case POT_SPEED: + /* Refilled potions of speed provide an extreme but short-lived + burst of speed */ + if(otmp->orefilled) { + youmonst.movement += (NORMAL_SPEED * 2 * (2 + bcsign(otmp))) / (otmp->odiluted ? 4 : 3); + +#ifdef STEED + /* Your steed can't keep up with you! */ + if (u.usteed) + dismount_steed(DISMOUNT_FELL); +#endif + + int normal = youmonst.data->mmove; + + if (Very_fast) { /* speed boots or potion */ + /* average movement is 1.67 times normal */ + normal += NORMAL_SPEED * 2 / 3; + } else if (Fast) { + /* average movement is 1.33 times normal */ + normal += NORMAL_SPEED / 3; + } + + if(youmonst.movement > normal * 2) { + pline_The("%s rips at your %s!", Underwater ? "water" : "wind", body_part(FACE)); + losehp(rnd(youmonst.movement - normal * 2), Underwater ? "water friction" : "air friction", KILLED_BY); + } + break; + } if(Wounded_legs && !otmp->cursed #ifdef STEED && !u.usteed /* heal_legs() would heal steeds legs */ @@ -748,9 +872,19 @@ peffects(otmp) break; case POT_BLINDNESS: if(Blind) nothing++; - make_blinded(itimeout_incr(Blinded, - rn1(200, 250 - 125 * bcsign(otmp))), - (boolean)!Blind); + if(otmp->orefilled) { //Blindness to invisible things only + if(!See_invisible) + nothing++; + else { + if(otmp->cursed) + HSee_invisible &= !FROMOUTSIDE; + set_itimeout(&HSee_invisible, 0); + } + } else { + make_blinded(itimeout_incr(Blinded, + rn1(200, 250 - 125 * bcsign(otmp))), + (boolean)!Blind); + } break; case POT_GAIN_LEVEL: if (otmp->cursed) { @@ -760,8 +894,8 @@ peffects(otmp) Can_rise_up(u.ux, u.uy, &u.uz)) { const char *riseup ="rise up, through the %s!"; if(ledger_no(&u.uz) == 1) { - You(riseup, ceiling(u.ux,u.uy)); - goto_level(&earth_level, FALSE, FALSE, FALSE); + You(riseup, otmp->orefilled ? "stairwell" : ceiling(u.ux,u.uy)); + goto_level(&earth_level, otmp->orefilled, FALSE, FALSE); } else { register int newlev = depth(&u.uz)-1; d_level newlevel; @@ -770,14 +904,31 @@ peffects(otmp) if(on_level(&newlevel, &u.uz)) { pline("It tasted bad."); break; - } else You(riseup, ceiling(u.ux,u.uy)); - goto_level(&newlevel, FALSE, FALSE, FALSE); + } else You(riseup, otmp->orefilled ? "stairwell" : ceiling(u.ux,u.uy)); + goto_level(&newlevel, otmp->orefilled, FALSE, FALSE); } } else You("have an uneasy feeling."); break; } - pluslvl(FALSE); + if(!otmp->orefilled) + pluslvl(FALSE); + else { /* Refilled potions don't increase max HP/energy */ + int uhpmax = u.uhpmax; + int uhp = u.uhp; + int mhmax = u.mhmax; + int mh = u.mh; + int uenmax = u.uenmax; + int uen = u.uen; + pluslvl(FALSE); + u.uhpmax = uhpmax; + u.uhp = uhp; + u.mhmax = mhmax; + u.mh = mh; + u.uenmax = uenmax; + u.uen = uen; + You("feel small."); + } if (otmp->blessed) /* blessed potions place you at a random spot in the * middle of the new level instead of the low point @@ -787,13 +938,13 @@ peffects(otmp) case POT_HEALING: You_feel("better."); healup(d(6 + 2 * bcsign(otmp), 4), - !otmp->cursed ? 1 : 0, !!otmp->blessed, !otmp->cursed); + !(otmp->cursed || otmp->orefilled) ? 1 : 0, !!otmp->blessed, !otmp->cursed); exercise(A_CON, TRUE); break; case POT_EXTRA_HEALING: You_feel("much better."); - healup(d(6 + 2 * bcsign(otmp), 8), - otmp->blessed ? 5 : !otmp->cursed ? 2 : 0, + healup(d(6 + 2 * bcsign(otmp), 8), otmp->orefilled ? 0 : + (otmp->blessed ? 5 : !otmp->cursed ? 2 : 0), !otmp->cursed, TRUE); (void) make_hallucinated(0L,TRUE,0L); exercise(A_CON, TRUE); @@ -801,7 +952,7 @@ peffects(otmp) break; case POT_FULL_HEALING: You_feel("completely healed."); - healup(400, 4+4*bcsign(otmp), !otmp->cursed, TRUE); + healup(400, otmp->orefilled ? 0 : (4+4*bcsign(otmp)), !otmp->cursed, TRUE); /* Restore one lost level if blessed */ if (otmp->blessed && u.ulevel < u.ulevelmax) { /* when multiple levels have been lost, drinking @@ -817,6 +968,9 @@ peffects(otmp) case SPE_LEVITATION: if (otmp->cursed) HLevitation &= ~I_SPECIAL; if(!Levitation) { + /* Refilled potion can only extend levitation, not begin it */ + if(otmp->orefilled) + break; /* kludge to ensure proper operation of float_up() */ HLevitation = 1; float_up(); @@ -838,9 +992,9 @@ peffects(otmp) } else nothing++; if (otmp->blessed) { - incr_itimeout(&HLevitation, rn1(50,250)); + incr_itimeout(&HLevitation, rn1(50, 250)); HLevitation |= I_SPECIAL; - } else incr_itimeout(&HLevitation, rn1(140,10)); + } else incr_itimeout(&HLevitation, rn1(140, 10)); spoteffects(FALSE); /* for sinks */ break; case POT_GAIN_ENERGY: /* M. Stephenson */ @@ -850,10 +1004,14 @@ peffects(otmp) else pline("Magical energies course through your body."); num = rnd(5) + 5 * otmp->blessed + 1; - u.uenmax += (otmp->cursed) ? -num : num; + if(!otmp->orefilled) /* Refilled potions don't increase (or decrease) max HP/energy */ + u.uenmax += (otmp->cursed) ? -num : num; + else + num *= 2; u.uen += (otmp->cursed) ? -num : num; if(u.uenmax <= 0) u.uenmax = 0; if(u.uen <= 0) u.uen = 0; + else if(u.uen > u.uenmax) u.uen = u.uenmax; flags.botl = 1; exercise(A_WIS, TRUE); } @@ -895,7 +1053,12 @@ peffects(otmp) case POT_POLYMORPH: You_feel("a little %s.", Hallucination ? "normal" : "strange"); if (!Unchanging) polyself(FALSE); + if(otmp->orefilled && Upolyd) + u.mtimedone /= 3; break; + case POT_NOTHING: + pline("This potion is empty!"); + return(0); default: impossible("What a funny potion! (%u)", otmp->otyp); return(0); @@ -990,8 +1153,8 @@ boolean your_fault; mon->mhp--; } - /* oil doesn't instantly evaporate */ - if (obj->otyp != POT_OIL && cansee(mon->mx,mon->my)) + /* oil doesn't instantly evaporate, empty potion has nothing to evaporate */ + if (obj->otyp != POT_OIL && obj->otyp != POT_NOTHING && cansee(mon->mx,mon->my)) pline("%s.", Tobjnam(obj, "evaporate")); if (isyou) { @@ -1146,6 +1309,7 @@ boolean your_fault; case POT_FRUIT_JUICE: case POT_MONSTER_DETECTION: case POT_OBJECT_DETECTION: + case POT_NOTHING: break; */ } @@ -1305,6 +1469,7 @@ register struct obj *obj; case POT_MONSTER_DETECTION: case POT_OBJECT_DETECTION: case POT_OIL: + case POT_NOTHING: break; */ } @@ -1443,11 +1608,20 @@ register struct obj *obj; update_inventory(); return (TRUE); } - pline("%s %s%s.", Your_buf, aobjnam(obj,"dilute"), - obj->odiluted ? " further" : ""); - if(obj->unpaid && costly_spot(u.ux, u.uy)) { - You("dilute it, you pay for it."); - bill_dummy_object(obj); + if (obj->otyp == POT_NOTHING) { + pline("%s %s with water.", Your_buf, aobjnam(obj,"fill")); + if(obj->unpaid && costly_spot(u.ux, u.uy)) { + You("use it, you pay for it."); + bill_dummy_object(obj); + } + obj->odiluted = 1; + } else { + pline("%s %s%s.", Your_buf, aobjnam(obj,"dilute"), + obj->odiluted ? " further" : ""); + if(obj->unpaid && costly_spot(u.ux, u.uy)) { + You("dilute it, you pay for it."); + bill_dummy_object(obj); + } } if (obj->odiluted) { obj->odiluted = 0; @@ -1531,6 +1705,7 @@ dodip() char allowall[2]; short mixture; char qbuf[QBUFSZ], Your_buf[BUFSZ]; + boolean obj_needs_reinventory; allowall[0] = ALL_CLASSES; allowall[1] = '\0'; if(!(obj = getobj(allowall, "dip"))) @@ -1568,14 +1743,45 @@ dodip() pline("That is a potion bottle, not a Klein bottle!"); return 0; } + if (potion->orefilled && potion->otyp != POT_NOTHING && obj->quan > 1L) { + obj = splitobj(obj, 1L); + obj_needs_reinventory = TRUE; + } else { + obj_needs_reinventory = FALSE; + } potion->in_use = TRUE; /* assume it will be used up */ - if(potion->otyp == POT_WATER) { + if(potion->otyp == POT_NOTHING) { + pline("Nothing happens."); + makeknown(potion->otyp); + potion->in_use = FALSE; /* didn't go poof */ + return(1); + } else if(obj->otyp == POT_NOTHING) { + /* You can refill an empty bottle from a potion... but only four at a time! */ + if (obj->quan > 4L) { + obj = splitobj(obj, 4L); + obj_needs_reinventory = TRUE; + } + obj->otyp = potion->otyp; + obj->odiluted = potion->odiluted; + if(obj->blessed) { + obj->blessed = obj->cursed ? 0 : potion->blessed; + obj->cursed = 0; + } else { + obj->blessed = obj->cursed ? 0 : potion->blessed; + obj->cursed = potion->cursed; + } + useup(potion); + if(obj_needs_reinventory) + reinventory(obj); + leavebottle(); + return(1); + } else if(potion->otyp == POT_WATER) { boolean useeit = !Blind; if (useeit) (void) Shk_Your(Your_buf, obj); if (potion->blessed) { if (obj->cursed) { if (useeit) - pline("%s %s %s.", + pline("%s %s %s.", Your_buf, aobjnam(obj, "softly glow"), hcolor(NH_AMBER)); @@ -1586,11 +1792,14 @@ dodip() !(objects[potion->otyp].oc_uname)) docall(potion); useup(potion); + if(obj_needs_reinventory) + reinventory(obj); + leavebottle(); return(1); } else if(!obj->blessed) { if (useeit) { - tmp = hcolor(NH_LIGHT_BLUE); - pline("%s %s with a%s %s aura.", + tmp = hcolor(NH_LIGHT_BLUE); + pline("%s %s with a%s %s aura.", Your_buf, aobjnam(obj, "softly glow"), index(vowels, *tmp) ? "n" : "", tmp); @@ -1602,7 +1811,7 @@ dodip() } else if (potion->cursed) { if (obj->blessed) { if (useeit) - pline("%s %s %s.", + pline("%s %s %s.", Your_buf, aobjnam(obj, "glow"), hcolor((const char *)"brown")); @@ -1611,8 +1820,8 @@ dodip() goto poof; } else if(!obj->cursed) { if (useeit) { - tmp = hcolor(NH_BLACK); - pline("%s %s with a%s %s aura.", + tmp = hcolor(NH_BLACK); + pline("%s %s with a%s %s aura.", Your_buf, aobjnam(obj, "glow"), index(vowels, *tmp) ? "n" : "", tmp); @@ -1623,7 +1832,7 @@ dodip() } } else if (get_wet(obj)) - goto poof; + goto poof; } else if (obj->otyp == POT_POLYMORPH || potion->otyp == POT_POLYMORPH) { /* some objects can't be polymorphed */ @@ -1654,6 +1863,8 @@ dodip() makeknown(POT_POLYMORPH); useup(potion); prinv((char *)0, obj, 0L); + /* Don't need to reinventory(), poly_obj did that */ + leavebottle(); return 1; } else { pline("Nothing seems to happen."); @@ -1719,6 +1930,9 @@ dodip() } useup(potion); + if(obj_needs_reinventory) + reinventory(obj); + leavebottle(); return(1); } @@ -1824,6 +2038,9 @@ dodip() exercise(A_WIS, wisx); makeknown(potion->otyp); useup(potion); + if(obj_needs_reinventory) + reinventory(obj); + leavebottle(); return 1; } more_dips: @@ -1852,6 +2069,7 @@ dodip() obj->age += 2*potion->age; /* burns more efficiently */ if (obj->age > 1500L) obj->age = 1500L; useup(potion); + leavebottle(); exercise(A_WIS, TRUE); } makeknown(POT_OIL); @@ -1913,15 +2131,14 @@ dodip() docall(&fakeobj); } } - obj_extract_self(singlepotion); - singlepotion = hold_another_object(singlepotion, - "You juggle and drop %s!", - doname(singlepotion), (const char *)0); + reinventory(singlepotion); update_inventory(); return(1); } pline("Interesting..."); + if(obj_needs_reinventory) + reinventory(obj); return(1); } diff -rup source-orig\src\read.c source-main\src\read.c --- source-orig\src\read.c Sun Dec 07 17:39:13 2003 +++ source-main\src\read.c Sat Dec 05 22:16:06 2009 @@ -17,6 +17,8 @@ #ifdef OVLB +extern void FDECL(reinventory, (struct obj *)); + boolean known; static NEARDATA const char readable[] = @@ -198,6 +200,8 @@ struct obj *obj; if (obj->oclass == RING_CLASS) return (boolean)(objects[obj->otyp].oc_charged && (obj->known || objects[obj->otyp].oc_uname)); + if (obj->oclass == POTION_CLASS) + return (boolean)(obj->dknown && obj->orefilled); if (is_weptool(obj)) /* specific check before general tools */ return FALSE; if (obj->oclass == TOOL_CLASS) @@ -293,6 +297,30 @@ int curse_bless; /* oartifact: if a touch-sensitive artifact ring is ever created the above will need to be revised */ } + + } else if (obj->oclass == POTION_CLASS) { + int num = rn1(7, 4); + if(num > obj->quan) + num = obj->quan; + num = rnd(num); + if(num < obj->quan) + obj = splitobj(obj, num); + else + num = 0; /* Now marks that the potion(s) need reinventory'd */ + if(curse_bless < 0) { + if(obj->otyp != POT_OIL && obj->otyp != POT_NOTHING) { + Your(aobjnam(obj,"evaporate")); + obj->otyp = POT_NOTHING; + obj->orefilled = 1; + obj->odiluted = 0; + } + } else { + obj->orefilled = 0; + if(curse_bless > 0) + obj->odiluted = 0; + } + if(num) + reinventory(obj); } else if (obj->oclass == TOOL_CLASS) { int rechrg = (int)obj->recharged; diff -rup source-orig\src\trap.c source-main\src\trap.c --- source-orig\src\trap.c Sun Dec 07 17:39:13 2003 +++ source-main\src\trap.c Fri Dec 04 17:59:14 2009 @@ -2655,7 +2655,7 @@ xchar x, y; destroy_strings[dindx*3 + 1] : destroy_strings[dindx*3]); delobj(obj); retval++; - } else if (obj->oclass == POTION_CLASS) { + } else if (obj->oclass == POTION_CLASS && obj->otyp != POT_NOTHING) { dindx = 1; if (in_sight) pline("%s %s.", Yname2(obj), (obj->quan > 1) ? diff -rup source-orig\src\zap.c source-main\src\zap.c --- source-orig\src\zap.c Sun Dec 07 17:39:13 2003 +++ source-main\src\zap.c Fri Dec 04 18:48:46 2009 @@ -1282,7 +1282,7 @@ poly_obj(obj, id) otmp->oeroded = obj->oeroded; otmp->oeroded2 = obj->oeroded2; if (!is_flammable(otmp) && !is_rustprone(otmp)) otmp->oeroded = 0; - if (!is_corrodeable(otmp) && !is_rottable(otmp)) otmp->oeroded2 = 0; + if (!is_corrodeable(otmp) && !is_rottable(otmp) && otmp->oclass != POTION_CLASS) otmp->oeroded2 = 0; if (is_damageable(otmp)) otmp->oerodeproof = obj->oerodeproof; @@ -3842,7 +3842,7 @@ register int osym, dmgtyp; #endif switch(dmgtyp) { case AD_COLD: - if(osym == POTION_CLASS && obj->otyp != POT_OIL) { + if(osym == POTION_CLASS && obj->otyp != POT_OIL && obj->otyp != POT_NOTHING) { quan = obj->quan; dindx = 0; dmg = rnd(4); @@ -3851,7 +3851,7 @@ register int osym, dmgtyp; case AD_FIRE: xresist = (Fire_resistance && obj->oclass != POTION_CLASS); - if (obj->otyp == SCR_FIRE || obj->otyp == SPE_FIREBALL) + if (obj->otyp == SCR_FIRE || obj->otyp == SPE_FIREBALL || obj->otyp == POT_NOTHING) skip++; if (obj->otyp == SPE_BOOK_OF_THE_DEAD) { skip++;