clean up messages when you stop levitation while riding a flying steed
account for all attacks when determining max_passive_dmg
dipping in acid can erode the dipped object
+various actions--such as enchanting--performed on an unpaid shop object
+ either force the hero to buy the item (when its value is lowered) or
+ increase the current bill (when its value is raised)
Platform- and/or Interface-Specific Fixes
E struct obj *FDECL(splitobj, (struct obj *,long));
E void FDECL(replace_object, (struct obj *,struct obj *));
E void FDECL(bill_dummy_object, (struct obj *));
+E void FDECL(costly_alteration, (struct obj *,int));
E struct obj *FDECL(mksobj, (int,BOOLEAN_P,BOOLEAN_P));
E int FDECL(bcsign, (struct obj *));
E int FDECL(weight, (struct obj *));
E long FDECL(contained_cost, (struct obj *,struct monst *,long,BOOLEAN_P, BOOLEAN_P));
E long FDECL(contained_gold, (struct obj *));
E void FDECL(picked_container, (struct obj *));
+E void FDECL(alter_cost, (struct obj *,long));
E long FDECL(unpaid_cost, (struct obj *));
E boolean FDECL(billable, (struct monst **,struct obj *,CHAR_P,BOOLEAN_P));
E void FDECL(addtobill, (struct obj *,BOOLEAN_P,BOOLEAN_P,BOOLEAN_P));
-/* SCCS Id: @(#)hack.h 3.5 2005/03/07 */
+/* SCCS Id: @(#)hack.h 3.5 2005/03/28 */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */
#define SELL_DELIBERATE (1)
#define SELL_DONTSELL (2)
+/* alteration types--keep in synch with costly_alteration(mkobj.c) */
+#define COST_CANCEL 0 /* standard cancellation */
+#define COST_DRAIN 1 /* drain life upon an object */
+#define COST_UNCHRG 2 /* cursed charging */
+#define COST_UNBLSS 3 /* unbless (devalues holy water) */
+#define COST_UNHOLY 4 /* uncurse (devalues unholy water) */
+#define COST_DECHNT 5 /* disenchant weapons or armor */
+#define COST_DEGRD 6 /* removal of rustproofing, dulling via engraving */
+#define COST_DILUTE 7 /* potion dilution */
+#define COST_ERASE 8 /* scroll or spellbook blanking */
+#define COST_BURN 9 /* dipped into flaming oil */
+#define COST_NUTRLZ 10 /* neutralized via unicorn horn */
+#define COST_DSTROY 11 /* wand breaking (bill first, useup later) */
+#define COST_SPLAT 12 /* cream pie to own face (ditto) */
+#define COST_BITE 13 /* start eating food */
+#define COST_OPEN 14 /* open tin */
+
/*
* This is the way the game ends. If these are rearranged, the arrays
* in end.c and topten.c will need to be changed. Some parts of the
-/* SCCS Id: @(#)apply.c 3.5 2005/01/05 */
+/* SCCS Id: @(#)apply.c 3.5 2005/03/28 */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */
if (obj->where == OBJ_MINVENT ? cansee(x,y) : !Blind)
pline("%s %s light!", Yname2(obj), otense(obj, "catch"));
if (obj->otyp == POT_OIL) makeknown(obj->otyp);
- if (obj->unpaid && costly_spot(u.ux, u.uy) && (obj->where == OBJ_INVENT)) {
+ if (carried(obj) && obj->unpaid && costly_spot(u.ux, u.uy)) {
/* if it catches while you have it, then it's your tough luck */
check_unpaid(obj);
verbalize("That's in addition to the cost of %s %s, of course.",
Blind ? "." : " brightly!");
if (obj->unpaid && costly_spot(u.ux, u.uy) &&
obj->age == 20L * (long)objects[obj->otyp].oc_cost) {
- const char *ithem = obj->quan > 1L ? "them" : "it";
+ const char *ithem = (obj->quan > 1L) ? "them" : "it";
+
verbalize("You burn %s, you bought %s!", ithem, ithem);
bill_dummy_object(obj);
}
You_cant("see through all the sticky goop on your %s.",
body_part(FACE));
}
- if (obj->unpaid) {
- verbalize("You used it, you bought it!");
- bill_dummy_object(obj);
- }
+ /* useup() is appropriate, but we want costly_alteration()'s message */
+ costly_alteration(obj, COST_SPLAT);
obj_extract_self(obj);
delobj(obj);
return(0);
*/
if (obj->unpaid) {
check_unpaid(obj); /* Extra charge for use */
- bill_dummy_object(obj);
+ costly_alteration(obj, COST_DSTROY);
}
current_wand = obj; /* destroy_item might reset this */
-/* SCCS Id: @(#)do.c 3.5 2004/09/10 */
+/* SCCS Id: @(#)do.c 3.5 2005/03/28 */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */
{
if (!obj) {
return;
- } else if ((Is_container(obj) || obj->otyp == STATUE) && obj->cobj) {
+ } else if (Has_contents(obj)) {
struct obj *contents;
- for(contents=obj->cobj; contents; contents=contents->nobj)
+
+ for (contents = obj->cobj; contents; contents = contents->nobj)
obj_no_longer_held(contents);
}
- switch(obj->otyp) {
+ switch (obj->otyp) {
case CRYSKNIFE:
/* KMH -- Fixed crysknives have only 10% chance of reverting */
/* only changes when not held by player or monster */
if (!obj->oerodeproof || !rn2(10)) {
+ /* if monsters aren't moving, assume player is responsible */
+ if (!context.mon_moving && !program_state.gameover)
+ costly_alteration(obj, COST_DEGRD);
obj->otyp = WORM_TOOTH;
obj->oerodeproof = 0;
}
-/* SCCS Id: @(#)eat.c 3.5 2005/03/09 */
+/* SCCS Id: @(#)eat.c 3.5 2005/03/28 */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */
STATIC_PTR int NDECL(eatmdone);
STATIC_PTR int NDECL(eatfood);
-STATIC_PTR void FDECL(costly_tin, (const char*));
+STATIC_PTR void FDECL(costly_tin, (int));
STATIC_PTR int NDECL(opentin);
STATIC_PTR int NDECL(unfaint);
}
if (!otmp->oeaten) {
- if(((!carried(otmp) && costly_spot(otmp->ox, otmp->oy) &&
- !otmp->no_charge)
- || otmp->unpaid)) {
- /* create a dummy duplicate to put on bill */
- verbalize("You bit it, you bought it!");
- bill_dummy_object(otmp);
- }
+ costly_alteration(otmp, COST_BITE);
otmp->oeaten = (otmp->otyp == CORPSE ?
mons[otmp->corpsenm].cnutrit :
objects[otmp->otyp].oc_nutrition);
* will split() context.tin.tin if necessary */
STATIC_PTR
void
-costly_tin(verb)
- const char* verb; /* if 0, the verb is "open" */
+costly_tin(alter_type)
+int alter_type; /* COST_xxx */
{
- if(((!carried(context.tin.tin) &&
- costly_spot(context.tin.tin->ox, context.tin.tin->oy) &&
- !context.tin.tin->no_charge)
- || context.tin.tin->unpaid)) {
- verbalize("You %s it, you bought it!", verb ? verb : "open");
- if(context.tin.tin->quan > 1L) {
- context.tin.tin = splitobj(context.tin.tin, 1L);
- if (context.tin.tin)
- context.tin.o_id = context.tin.tin->o_id;
- }
- bill_dummy_object(context.tin.tin);
+ struct obj *tin = context.tin.tin;
+
+ if (carried(tin) ? tin->unpaid :
+ (costly_spot(tin->ox, tin->oy) && !tin->no_charge)) {
+ if (tin->quan > 1L) {
+ tin = context.tin.tin = splitobj(tin, 1L);
+ context.tin.o_id = tin->o_id;
}
+ costly_alteration(tin, alter_type);
+ }
}
int
if(context.tin.tin->otrapped ||
(context.tin.tin->cursed && context.tin.tin->spe != -1 && !rn2(8))) {
b_trapped("tin", 0);
- costly_tin("destroyed");
+ costly_tin(COST_DSTROY);
goto use_me;
}
if (mnum == NON_PM) {
pline("It turns out to be empty.");
context.tin.tin->dknown = context.tin.tin->known = TRUE;
- costly_tin((const char*)0);
+ costly_tin(COST_OPEN);
goto use_me;
}
r = tin_variety(context.tin.tin);
if (!Hallucination)
context.tin.tin->dknown = context.tin.tin->known = TRUE;
if (flags.verbose) You("discard the open tin.");
- costly_tin((const char*)0);
+ costly_tin(COST_OPEN);
goto use_me;
}
/* in case stop_occupation() was called on previous meal */
cpostfx(mnum);
/* charge for one at pre-eating cost */
- costly_tin((const char*)0);
+ costly_tin(COST_OPEN);
/* check for vomiting added by GAN 01/16/87 */
if(tintxts[r].nut < 0) make_vomiting((long)rn1(15,10), FALSE);
context.tin.tin->dknown = context.tin.tin->known = TRUE;
if (flags.verbose)
You("discard the open tin.");
- costly_tin((const char*)0);
+ costly_tin(COST_OPEN);
goto use_me;
}
context.tin.tin->dknown = context.tin.tin->known = TRUE;
- costly_tin((const char*)0);
+ costly_tin(COST_OPEN);
if (!context.tin.tin->cursed)
pline("This makes you feel like %s!",
-/* SCCS Id: @(#)engrave.c 3.5 2004/01/03 */
+/* SCCS Id: @(#)engrave.c 3.5 2005/03/28 */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */
* "ere", then "th".
*/
pline("%s dull.", Yobjnam2(otmp, "get"));
- if (otmp->unpaid) {
- struct monst *shkp = shop_keeper(*u.ushops);
- if (shkp) {
- You("damage it, you pay for it!");
- bill_dummy_object(otmp);
- }
- }
+ costly_alteration(otmp, COST_DEGRD);
if (len > maxelen) {
multi = -maxelen;
otmp->spe = -3;
* an object which is different from what it started out as; the "I x"
* command needs to display the original object.
*
+ * [BUG: The cost might end up being different if item originally had a
+ * surcharge but doesn't get one now or vice versa. Having the dummy keep
+ * the same o_id value as the original would avoid this; is that viable?
+ * (Mustn't give the original itself a new o_id, so can't just swap them.)]
+ *
* The caller is responsible for checking otmp->unpaid and
* costly_spot(u.ux, u.uy). This function will make otmp no charge.
*
return;
}
+/* alteration types; must match COST_xxx macros in hack.h */
+static const char * const alteration_verbs[] = {
+ "cancel", "drain", "uncharge", "unbless", "uncurse",
+ "disenchant", "degrade", "dilute", "erase", "burn",
+ "neutralize", "destroy", "splatter", "bite", "open",
+};
+
+/* possibly bill for an object which the player has just modified */
+void
+costly_alteration(obj, alter_type)
+struct obj *obj;
+int alter_type;
+{
+ xchar ox, oy;
+ char objroom;
+ const char *those, *them, *what;
+ struct monst *shkp = 0;
+
+ if (alter_type < 0 || alter_type >= SIZE(alteration_verbs)) {
+ impossible("invalid alteration type (%d)", alter_type);
+ alter_type = 0;
+ }
+
+ ox = oy = 0; /* lint suppression */
+ objroom = '\0'; /* ditto */
+ if (carried(obj) || obj->where == OBJ_FREE) {
+ /* OBJ_FREE catches obj_no_longer_held()'s transformation
+ of crysknife back into worm tooth; the object has been
+ removed from inventory but not necessarily placed at
+ its new location yet--the unpaid flag will still be set
+ if this item is owned by a shop */
+ if (!obj->unpaid) return;
+ } else {
+ /* this get_obj_location shouldn't fail, but if it does,
+ use hero's location */
+ if (!get_obj_location(obj, &ox, &oy, CONTAINED_TOO))
+ ox = u.ux, oy = u.uy;
+ objroom = *in_rooms(ox, oy, SHOPBASE);
+ /* if no shop cares about it, we're done */
+ if (!billable(&shkp, obj, objroom, FALSE)) return;
+ }
+
+ if (obj->quan == 1L)
+ those = "that", them = "it";
+ else
+ those = "those", them = "them";
+
+ switch (obj->where) {
+ case OBJ_FREE: /* obj_no_longer_held() */
+ case OBJ_INVENT:
+ what = simple_typename(obj->otyp);
+ if (obj->quan != 1L) what = makeplural(what);
+ verbalize("You %s %s %s, you pay for %s!",
+ alteration_verbs[alter_type], those, what, them);
+ bill_dummy_object(obj);
+ break;
+ case OBJ_FLOOR:
+ if (costly_spot(u.ux, u.uy) && objroom == *u.ushops) {
+ verbalize("You %s %s, you pay for %s!",
+ alteration_verbs[alter_type], those, them);
+ bill_dummy_object(obj);
+ } else {
+ (void) stolen_value(obj, ox, oy, FALSE, FALSE);
+ }
+ break;
+ }
+}
+
static const char dknowns[] = {
WAND_CLASS, RING_CLASS, POTION_CLASS, SCROLL_CLASS,
GEM_CLASS, SPBOOK_CLASS, WEAPON_CLASS, TOOL_CLASS, 0
-/* SCCS Id: @(#)potion.c 3.5 2004/12/21 */
+/* SCCS Id: @(#)potion.c 3.5 2005/03/26 */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */
}
pline("%s%s.", Yobjnam2(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);
- }
+ costly_alteration(obj, COST_DILUTE);
if (obj->odiluted) {
obj->odiluted = 0;
-#ifdef UNIXPC
obj->blessed = FALSE;
obj->cursed = FALSE;
-#else
- obj->blessed = obj->cursed = FALSE;
-#endif
obj->otyp = POT_WATER;
- } else obj->odiluted++;
+ } else
+ obj->odiluted++;
update_inventory();
return TRUE;
case SCROLL_CLASS:
&& obj->otyp != SCR_MAIL
#endif
) {
- if (!Blind) {
- boolean oq1 = obj->quan == 1L;
- pline_The("scroll%s %s.",
- oq1 ? "" : "s", otense(obj, "fade"));
- }
- if(obj->unpaid && costly_spot(u.ux, u.uy)) {
- You("erase it, you pay for it.");
- bill_dummy_object(obj);
- }
+ if (!Blind)
+ pline_The("scroll%s %s.",
+ plur(obj->quan), otense(obj, "fade"));
+ costly_alteration(obj, COST_ERASE);
obj->otyp = SCR_BLANK_PAPER;
obj->spe = 0;
update_inventory();
if (obj->otyp != SPE_BLANK_PAPER) {
if (obj->otyp == SPE_BOOK_OF_THE_DEAD) {
- pline("%s suddenly heats up; steam rises and it remains dry.",
- The(xname(obj)));
+ pline(
+ "%s suddenly heats up; steam rises and it remains dry.",
+ The(xname(obj)));
} else {
- if (!Blind) {
- boolean oq1 = obj->quan == 1L;
- pline_The("spellbook%s %s.",
- oq1 ? "" : "s", otense(obj, "fade"));
- }
- if(obj->unpaid && costly_spot(u.ux, u.uy)) {
- You("erase it, you pay for it.");
- bill_dummy_object(obj);
- }
+ if (!Blind)
+ pline_The("spellbook%s %s.",
+ plur(obj->quan),
+ otense(obj, "fade"));
+ costly_alteration(obj, COST_ERASE);
obj->otyp = SPE_BLANK_PAPER;
update_inventory();
}
potion->in_use = TRUE; /* assume it will be used up */
if(potion->otyp == POT_WATER) {
boolean useeit = !Blind || (obj == ublindf && Blindfolded_only);
+
if (potion->blessed) {
if (obj->cursed) {
if (useeit)
pline("%s %s.",
Yobjnam2(obj, "softly glow"),
hcolor(NH_AMBER));
+ obj->bknown = 1;
+ if (obj->otyp == POT_WATER && obj->unpaid)
+ costly_alteration(obj, COST_UNHOLY);
uncurse(obj);
- obj->bknown=1;
poof:
if(!(objects[potion->otyp].oc_name_known) &&
!(objects[potion->otyp].oc_uname))
Yobjnam2(obj, "softly glow"),
index(vowels, *tmp) ? "n" : "", tmp);
}
+ obj->bknown = 1;
bless(obj);
- obj->bknown=1;
+ if (obj->otyp == POT_WATER && obj->unpaid)
+ alter_cost(obj, 0L);
goto poof;
}
} else if (potion->cursed) {
pline("%s %s.",
Yobjnam2(obj, "glow"),
hcolor((const char *)"brown"));
+ obj->bknown = 1;
+ if (obj->otyp == POT_WATER && obj->unpaid)
+ costly_alteration(obj, COST_UNBLSS);
unbless(obj);
- obj->bknown=1;
goto poof;
} else if(!obj->cursed) {
if (useeit) {
Yobjnam2(obj, "glow"),
index(vowels, *tmp) ? "n" : "", tmp);
}
+ obj->bknown = 1;
curse(obj);
- obj->bknown=1;
+ if (obj->otyp == POT_WATER && obj->unpaid)
+ alter_cost(obj, 0L);
goto poof;
}
} else
/* catch_lit does all the work if true */
} else if (obj->oerodeproof || obj_resists(obj, 5, 95) ||
!is_flammable(obj) || obj->oclass == FOOD_CLASS) {
- pline("%s %s to burn for a moment.",
- Yname2(obj), otense(obj, "seem"));
+ pline("%s %s to burn for a moment but %s unharmed.",
+ Yname2(obj), otense(obj, "seem"), otense(obj, "are"));
} else {
if ((omat == PLASTIC || omat == PAPER) && !obj->oartifact)
obj->oeroded = MAX_ERODE;
obj->oeroded == MAX_ERODE ? "destroys" : "damages",
yname(obj),
obj->oeroded == MAX_ERODE ? '!' : '.');
+ costly_alteration(obj, COST_BURN);
if (obj->oeroded == MAX_ERODE) {
if (obj->owornmask) remove_worn_item(obj, TRUE);
obj_extract_self(obj);
obfree(obj, (struct obj *)0);
obj = (struct obj *) 0;
} else {
- /* we know it's carried */
- if (obj->unpaid) {
- /* create a dummy duplicate to put on bill */
- verbalize("You burnt it, you bought it!");
- bill_dummy_object(obj);
- }
obj->oeroded++;
}
}
if (potion->quan > 1L) {
singlepotion = splitobj(potion, 1L);
} else singlepotion = potion;
-
- if(singlepotion->unpaid && costly_spot(u.ux, u.uy)) {
- You("use it, you pay for it.");
- bill_dummy_object(singlepotion);
- }
+
+ costly_alteration(singlepotion, COST_NUTRLZ);
singlepotion->otyp = mixture;
singlepotion->blessed = 0;
if (mixture == POT_WATER)
-/* SCCS Id: @(#)read.c 3.5 2004/05/07 */
+/* SCCS Id: @(#)read.c 3.5 2005/03/28 */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */
stripspe(obj)
register struct obj *obj;
{
- if (obj->blessed) pline(nothing_happens);
- else {
- if (obj->spe > 0) {
- obj->spe = 0;
- if (obj->otyp == OIL_LAMP || obj->otyp == BRASS_LANTERN)
- obj->age = 0;
- pline("%s briefly.", Yobjnam2(obj, "vibrate"));
- } else pline(nothing_happens);
+ if (obj->blessed || obj->spe <= 0) {
+ pline(nothing_happens);
+ } else {
+ /* order matters: message, shop handling, actual transformation */
+ pline("%s briefly.", Yobjnam2(obj, "vibrate"));
+ costly_alteration(obj, COST_UNCHRG);
+ obj->spe = 0;
+ if (obj->otyp == OIL_LAMP || obj->otyp == BRASS_LANTERN)
+ obj->age = 0;
}
}
}
if (obj->spe >= lim) p_glow2(obj, NH_BLUE);
else p_glow1(obj);
+#if 0 /*[shop price doesn't vary by charge count]*/
+ /* update shop bill to reflect new higher price */
+ if (obj->unpaid) alter_cost(obj, 0L);
+#endif
}
} else if (obj->oclass == RING_CLASS &&
RIGHT_RING) : 0L;
pline("%s spins %sclockwise for a moment.",
Yname2(obj), s < 0 ? "counter" : "");
+ if (s < 0) costly_alteration(obj, COST_DECHNT);
/* cause attributes and/or properties to be updated */
if (is_on) Ring_off(obj);
obj->spe += s; /* update the ring while it's off */
if (is_on) setworn(obj, mask), Ring_on(obj);
/* oartifact: if a touch-sensitive artifact ring is
ever created the above will need to be revised */
+ /* update shop bill to reflect new higher price */
+ if (s > 0 && obj->unpaid) alter_cost(obj, 0L);
}
} else if (obj->oclass == TOOL_CLASS) {
int
seffects(sobj)
-register struct obj *sobj;
+struct obj *sobj;
{
- register int cval;
- register boolean confused = (Confusion != 0);
- register struct obj *otmp;
+ int cval;
+ boolean confused = (Confusion != 0),
+ old_erodeproof, new_erodeproof;
+ struct obj *otmp;
if (objects[sobj->otyp].oc_magic)
exercise(A_WIS, TRUE); /* just for trying */
case SCR_MAIL:
known = TRUE;
if (sobj->spe)
- pline("This seems to be junk mail addressed to the finder of the Eye of Larn.");
+ pline(
+ "This seems to be junk mail addressed to the finder of the Eye of Larn.");
/* note to the puzzled: the game Larn actually sends you junk
* mail if you win!
*/
return(1);
}
if(confused) {
- otmp->oerodeproof = !(sobj->cursed);
+ old_erodeproof = (otmp->oerodeproof != 0);
+ new_erodeproof = !sobj->cursed;
+ otmp->oerodeproof = 0; /* for messages */
if(Blind) {
otmp->rknown = FALSE;
pline("%s warm for a moment.",
pline("%s covered by a %s %s %s!",
Yobjnam2(otmp, "are"),
sobj->cursed ? "mottled" : "shimmering",
- hcolor(sobj->cursed ? NH_BLACK : NH_GOLDEN),
+ hcolor(sobj->cursed ? NH_BLACK : NH_GOLDEN),
sobj->cursed ? "glow" :
(is_shield(otmp) ? "layer" : "shield"));
}
- if (otmp->oerodeproof &&
+ if (new_erodeproof &&
(otmp->oeroded || otmp->oeroded2)) {
otmp->oeroded = otmp->oeroded2 = 0;
pline("%s as good as new!",
Yobjnam2(otmp, Blind ? "feel" : "look"));
}
+ if (old_erodeproof && !new_erodeproof) {
+ /* restore old_erodeproof before shop charges */
+ otmp->oerodeproof = 1;
+ costly_alteration(otmp, COST_DEGRD);
+ }
+ otmp->oerodeproof = new_erodeproof ? 1 : 0;
break;
}
/* elven armor vibrates warningly when enchanted beyond a limit */
/* assumes same order */
otmp->otyp = GRAY_DRAGON_SCALE_MAIL +
otmp->otyp - GRAY_DRAGON_SCALES;
- otmp->cursed = 0;
if (sobj->blessed) {
- otmp->spe++;
- otmp->blessed = 1;
- }
+ otmp->spe++;
+ if (!otmp->blessed) bless(otmp);
+ } else if (otmp->cursed)
+ uncurse(otmp);
otmp->known = 1;
setworn(otmp, W_ARM);
+ if (otmp->unpaid) alter_cost(otmp, 0L); /* shop bill */
break;
}
pline("%s %s%s%s%s for a %s.",
- Yname2(otmp),
- s == 0 ? "violently " : nul,
- otense(otmp, Blind ? "vibrate" : "glow"),
- (!Blind && !same_color) ? " " : nul,
- (Blind || same_color) ? nul : hcolor(sobj->cursed ? NH_BLACK : NH_SILVER),
- (s*s>1) ? "while" : "moment");
- otmp->cursed = sobj->cursed;
- if (!otmp->blessed || sobj->cursed)
- otmp->blessed = sobj->blessed;
+ Yname2(otmp),
+ s == 0 ? "violently " : nul,
+ otense(otmp, Blind ? "vibrate" : "glow"),
+ (!Blind && !same_color) ? " " : nul,
+ (Blind || same_color) ? nul :
+ hcolor(sobj->cursed ? NH_BLACK : NH_SILVER),
+ (s * s > 1) ? "while" : "moment");
+ /* [this cost handling will need updating if shop pricing is
+ ever changed to care about curse/bless status of armor] */
+ if (s < 0) costly_alteration(otmp, COST_DECHNT);
+ if (sobj->cursed && !otmp->cursed) curse(otmp);
+ else if (sobj->blessed && !otmp->blessed) bless(otmp);
if (s) {
otmp->spe += s;
adj_abon(otmp, s);
known = otmp->known;
+ /* update shop bill to reflect new higher price */
+ if (s > 0 && otmp->unpaid) alter_cost(otmp, 0L);
}
if ((otmp->spe > (special_armor ? 5 : 3)) &&
exercise(A_CON, FALSE);
return(1);
}
- otmp->oerodeproof = sobj->cursed;
+ old_erodeproof = (otmp->oerodeproof != 0);
+ new_erodeproof = (sobj->cursed != 0);
+ otmp->oerodeproof = 0; /* for messages */
p_glow2(otmp, NH_PURPLE);
+ if (old_erodeproof && !new_erodeproof) {
+ /* restore old_erodeproof before shop charges */
+ otmp->oerodeproof = 1;
+ costly_alteration(otmp, COST_DEGRD);
+ }
+ otmp->oerodeproof = new_erodeproof ? 1 : 0;
break;
}
if(!sobj->cursed || !otmp || !otmp->cursed) {
break;
case SCR_SCARE_MONSTER:
case SPE_CAUSE_FEAR:
- { register int ct = 0;
+ {
+ register int ct = 0;
register struct monst *mtmp;
for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
break;
case SCR_REMOVE_CURSE:
case SPE_REMOVE_CURSE:
- { register struct obj *obj;
- if(confused)
- if (Hallucination)
- You_feel("the power of the Force against you!");
- else
- You_feel("like you need some help.");
- else
- if (Hallucination)
- You_feel("in touch with the Universal Oneness.");
- else
- You_feel("like someone is helping you.");
+ {
+ register struct obj *obj;
+
+ You_feel(!Hallucination ?
+ (!confused ?
+ "like someone is helping you." :
+ "like you need some help.") :
+ (!confused ?
+ "in touch with the Universal Oneness." :
+ "the power of the Force against you!"));
if (sobj->cursed) {
pline_The("scroll disintegrates.");
if (sobj->blessed || wornmask ||
obj->otyp == LOADSTONE ||
(obj->otyp == LEASH && obj->leashmon)) {
+ unsigned save_bknown, save_cursed, save_blessed;
+ boolean was_cursed = !!obj->cursed,
+ was_blessed = !!obj->blessed,
+ was_normal = !(was_cursed || was_blessed);
+
if(confused) blessorcurse(obj, 2);
else uncurse(obj);
+ /* water price varies by curse/bless status */
+ if (obj->unpaid && obj->otyp == POT_WATER) {
+ if ((was_cursed && !obj->cursed) ||
+ (was_blessed && !obj->blessed)) {
+ /* make `Ix' more specific for this item */
+ save_bknown = obj->bknown;
+ obj->bknown = 1;
+ /* temporarily restore curse/bless to
+ obtain the right shop price (if potion
+ went from cursed directly to blessed
+ or vice versa its price didn't change
+ but hero will have to buy it anyway) */
+ save_cursed = obj->cursed;
+ obj->cursed = was_cursed ? 1 : 0;
+ save_blessed = obj->blessed;
+ obj->blessed = was_blessed ? 1 : 0;
+ costly_alteration(obj, was_cursed ?
+ COST_UNHOLY : COST_UNBLSS);
+ obj->bknown = save_bknown;
+ obj->cursed = save_cursed;
+ obj->blessed = save_blessed;
+ } else if (was_normal &&
+ (obj->blessed || obj->cursed)) {
+ alter_cost(obj, 0L);
+ }
+ } /* unpaid water */
}
}
}
*/
break;
case SCR_ENCHANT_WEAPON:
- if(uwep && (uwep->oclass == WEAPON_CLASS || is_weptool(uwep))
- && confused) {
- /* oclass check added 10/25/86 GAN */
- uwep->oerodeproof = !(sobj->cursed);
+ if (confused && uwep &&
+ (uwep->oclass == WEAPON_CLASS || is_weptool(uwep))) {
+ old_erodeproof = (uwep->oerodeproof != 0);
+ new_erodeproof = !sobj->cursed;
+ uwep->oerodeproof = 0; /* for messages */
if (Blind) {
uwep->rknown = FALSE;
Your("weapon feels warm for a moment.");
pline("%s as good as new!",
Yobjnam2(uwep, Blind ? "feel" : "look"));
}
- } else return !chwepon(sobj,
- sobj->cursed ? -1 :
- !uwep ? 1 :
- uwep->spe >= 9 ? (rn2(uwep->spe) == 0) :
- sobj->blessed ? rnd(3-uwep->spe/3) : 1);
- break;
+ if (old_erodeproof && !new_erodeproof) {
+ /* restore old_erodeproof before shop charges */
+ uwep->oerodeproof = 1;
+ costly_alteration(uwep, COST_DEGRD);
+ }
+ uwep->oerodeproof = new_erodeproof ? 1 : 0;
+ break;
+ }
+ return !chwepon(sobj,
+ sobj->cursed ? -1 :
+ !uwep ? 1 :
+ uwep->spe >= 9 ? (rn2(uwep->spe) == 0) :
+ sobj->blessed ? rnd(3 - uwep->spe / 3) : 1);
case SCR_TAMING:
case SPE_CHARM_MONSTER:
if (u.uswallow) {
}
punish(sobj);
break;
- case SCR_STINKING_CLOUD: {
- coord cc;
+ case SCR_STINKING_CLOUD:
+ {
+ coord cc;
You("have found a scroll of stinking cloud!");
known = TRUE;
return tmp;
}
+/* called when an item's value has been enhanced; if it happens to be
+ on any shop bill, update that bill to reflect the new higher price
+ [if the new price drops for some reason, keep the old one in place] */
+void
+alter_cost(obj, amt)
+struct obj *obj;
+long amt; /* if 0, use regular shop pricing, otherwise force amount;
+ if negative, use abs(amt) even if it's less than old cost */
+{
+ struct bill_x *bp = 0;
+ struct monst *shkp;
+ long new_price;
+
+ for (shkp = next_shkp(fmon, TRUE); shkp; shkp = next_shkp(shkp, TRUE))
+ if ((bp = onbill(obj, shkp, TRUE)) != 0) {
+ new_price = !amt ? get_cost(obj, shkp) : (amt < 0L) ? -amt : amt;
+ if (new_price > bp->price || amt < 0L) {
+ bp->price = new_price;
+ update_inventory();
+ }
+ break; /* done */
+ }
+ return;
+}
+
/* called from doinv(invent.c) for inventory of unpaid objects */
long
unpaid_cost(unp_obj)
-/* SCCS Id: @(#)wield.c 3.5 2003/01/29 */
+/* SCCS Id: @(#)wield.c 3.5 2005/03/28 */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */
if (otmp && otmp->oclass == SCROLL_CLASS) otyp = otmp->otyp;
- if(uwep->otyp == WORM_TOOTH && amount >= 0) {
+ if (uwep->otyp == WORM_TOOTH && amount >= 0) {
+ /* order: message, transformation, shop handling */
+ Your("%s is much sharper now.", simple_typename(WORM_TOOTH));
uwep->otyp = CRYSKNIFE;
uwep->oerodeproof = 0;
- Your("weapon seems sharper now.");
- uwep->cursed = 0;
+ if (uwep->cursed) uncurse(uwep);
+ /* update shop bill to reflect new higher value */
+ if (uwep->unpaid) alter_cost(uwep, 0L);
if (otyp != STRANGE_OBJECT) makeknown(otyp);
- return(1);
- }
-
- if(uwep->otyp == CRYSKNIFE && amount < 0) {
+ return 1;
+ } else if (uwep->otyp == CRYSKNIFE && amount < 0) {
+ /* order matters: message, shop handling, transformation */
+ Your("%s is much duller now.", simple_typename(CRYSKNIFE));
+ costly_alteration(uwep, COST_DEGRD); /* DECHNT? other? */
uwep->otyp = WORM_TOOTH;
uwep->oerodeproof = 0;
- Your("weapon seems duller now.");
if (otyp != STRANGE_OBJECT && otmp->bknown) makeknown(otyp);
- return(1);
+ return 1;
}
if (amount < 0 && uwep->oartifact && restrict_name(uwep, ONAME(uwep))) {
(amount > 0 || (amount < 0 && otmp->bknown)))
makeknown(otyp);
}
+ if (amount < 0) costly_alteration(uwep, COST_DECHNT);
uwep->spe += amount;
- if(amount > 0) uwep->cursed = 0;
+ if (amount > 0) {
+ if (uwep->cursed) uncurse(uwep);
+ /* update shop bill to reflect new higher price */
+ if (uwep->unpaid) alter_cost(uwep, 0L);
+ }
/*
* Enchantment, which normally improves a weapon, has an
-/* SCCS Id: @(#)zap.c 3.5 2005/03/18 */
+/* SCCS Id: @(#)zap.c 3.5 2005/03/28 */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */
/* kludge to use mondied instead of killed */
extern boolean m_using;
-STATIC_DCL void FDECL(costly_cancel, (struct obj *));
STATIC_DCL void FDECL(polyuse, (struct obj*, int, int));
STATIC_DCL void FDECL(create_polymon, (struct obj *, int));
STATIC_DCL boolean FDECL(zap_updown, (struct obj *));
return res;
}
-static const char charged_objs[] = { WAND_CLASS, WEAPON_CLASS, ARMOR_CLASS, 0 };
-
-STATIC_OVL void
-costly_cancel(obj)
-register struct obj *obj;
-{
- char objroom;
- struct monst *shkp = (struct monst *)0;
-
- if (obj->no_charge) return;
-
- switch (obj->where) {
- case OBJ_INVENT:
- if (obj->unpaid) {
- shkp = shop_keeper(*u.ushops);
- if (!shkp) return;
- Norep("You cancel an unpaid object, you pay for it!");
- bill_dummy_object(obj);
- }
- break;
- case OBJ_FLOOR:
- objroom = *in_rooms(obj->ox, obj->oy, SHOPBASE);
- shkp = shop_keeper(objroom);
- if (!shkp || !inhishop(shkp)) return;
- if (costly_spot(u.ux, u.uy) && objroom == *u.ushops) {
- Norep("You cancel it, you pay for it!");
- bill_dummy_object(obj);
- } else
- (void) stolen_value(obj, obj->ox, obj->oy, FALSE, FALSE);
- break;
- }
-}
-
/* cancel obj, possibly carried by you or a monster */
void
cancel_item(obj)
register struct obj *obj;
{
- boolean u_ring = (obj == uleft) || (obj == uright);
- register boolean holy = (obj->otyp == POT_WATER && obj->blessed);
+ boolean u_ring = (obj == uleft || obj == uright);
+ int otyp = obj->otyp;
- switch(obj->otyp) {
+ switch (otyp) {
case RIN_GAIN_STRENGTH:
if ((obj->owornmask & W_RING) && u_ring) {
ABON(A_STR) -= obj->spe;
break;
/* case RIN_PROTECTION: not needed */
}
- if (objects[obj->otyp].oc_magic
- || (obj->spe && (obj->oclass == ARMOR_CLASS ||
- obj->oclass == WEAPON_CLASS || is_weptool(obj)))
- || obj->otyp == POT_ACID || obj->otyp == POT_SICKNESS) {
+ if (objects[otyp].oc_magic ||
+ (obj->spe && (obj->oclass == ARMOR_CLASS ||
+ obj->oclass == WEAPON_CLASS || is_weptool(obj))) ||
+ otyp == POT_ACID || otyp == POT_SICKNESS ||
+ (otyp == WATER && (obj->blessed || obj->cursed))) {
if (obj->spe != ((obj->oclass == WAND_CLASS) ? -1 : 0) &&
- obj->otyp != WAN_CANCELLATION &&
- /* can't cancel cancellation */
- obj->otyp != MAGIC_LAMP &&
- obj->otyp != CANDELABRUM_OF_INVOCATION) {
- costly_cancel(obj);
+ otyp != WAN_CANCELLATION && /* can't cancel cancellation */
+ otyp != MAGIC_LAMP && /* cancelling doesn't remove djini */
+ otyp != CANDELABRUM_OF_INVOCATION) {
+ costly_alteration(obj, COST_CANCEL);
obj->spe = (obj->oclass == WAND_CLASS) ? -1 : 0;
}
switch (obj->oclass) {
case SCROLL_CLASS:
- costly_cancel(obj);
+ costly_alteration(obj, COST_CANCEL);
obj->otyp = SCR_BLANK_PAPER;
obj->spe = 0;
break;
case SPBOOK_CLASS:
- if (obj->otyp != SPE_CANCELLATION &&
- obj->otyp != SPE_BOOK_OF_THE_DEAD) {
- costly_cancel(obj);
+ if (otyp != SPE_CANCELLATION && otyp != SPE_BOOK_OF_THE_DEAD) {
+ costly_alteration(obj, COST_CANCEL);
obj->otyp = SPE_BLANK_PAPER;
}
break;
case POTION_CLASS:
- costly_cancel(obj);
- if (obj->otyp == POT_SICKNESS ||
- obj->otyp == POT_SEE_INVISIBLE) {
- /* 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.
- */
+ costly_alteration(obj, (otyp == WATER && obj->cursed) ?
+ COST_UNHOLY : COST_CANCEL);
+ if (otyp == POT_SICKNESS || otyp == POT_SEE_INVISIBLE) {
+ /* 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 */
obj->otyp = POT_FRUIT_JUICE;
} else {
- obj->otyp = POT_WATER;
+ obj->otyp = POT_WATER;
obj->odiluted = 0; /* same as any other water */
}
break;
}
}
- if (holy) costly_cancel(obj);
unbless(obj);
uncurse(obj);
#ifdef INVISIBLE_OBJECTS
+ /*[this will be insufficient if it ever reduces obj's shop value]*/
if (obj->oinvis) obj->oinvis = 0;
#endif
return;
return (FALSE);
/* Charge for the cost of the object */
- costly_cancel(obj); /* The term "cancel" is okay for now */
+ costly_alteration(obj, COST_DRAIN);
/* Drain the object and any implied effects */
obj->spe--;
delobj(obj);
}
+/* classes of items whose current charge count carries over across polymorph */
+static const char charged_objs[] = {
+ WAND_CLASS, WEAPON_CLASS, ARMOR_CLASS, '\0'
+};
+
/*
* Polymorph the object to the given object ID. If the ID is STRANGE_OBJECT
* then pick random object from the source's class (this is the standard