Merge fire-based erosion to common codepaths.

This finally eliminates all direct increases of `oeroded` and `oeroded2`
and moves them all to go via `erode_obj()`. They are still manipulated
directly in a few places, but not to erode objects.

This now merges the `fire_damage()` function to a common codepath, used
for items on lava and burning oil, but fire needs more work. There is
still a duplication between `destroy_item()` and `fire_damage()`; the
two codepaths should eventually be merged in some manner so that there
is only one codepath to say "an object was affected by fire". This path
might require some parameters, such as whether the fire will just erode
objects or burn them outright, but that can happen another day.
This commit is contained in:
Sean Hunt
2015-03-01 11:54:40 -05:00
parent 3acd3c4a00
commit 777328bd5c
13 changed files with 226 additions and 177 deletions

View File

@@ -2202,7 +2202,7 @@ E coord *FDECL(gettrack, (int,int));
/* ### trap.c ### */ /* ### trap.c ### */
E boolean FDECL(burnarmor,(struct monst *)); E boolean FDECL(burnarmor,(struct monst *));
E boolean FDECL(erode_obj, (struct obj *,const char *,int,BOOLEAN_P,BOOLEAN_P)); E int FDECL(erode_obj, (struct obj *,const char *,int,int));
E boolean FDECL(grease_protect, (struct obj *,const char *,struct monst *)); E boolean FDECL(grease_protect, (struct obj *,const char *,struct monst *));
E struct trap *FDECL(maketrap, (int,int,int)); E struct trap *FDECL(maketrap, (int,int,int));
E void FDECL(fall_through, (BOOLEAN_P)); E void FDECL(fall_through, (BOOLEAN_P));
@@ -2221,7 +2221,8 @@ E void NDECL(float_up);
E void FDECL(fill_pit, (int,int)); E void FDECL(fill_pit, (int,int));
E int FDECL(float_down, (long, long)); E int FDECL(float_down, (long, long));
E void NDECL(climb_pit); E void NDECL(climb_pit);
E int FDECL(fire_damage, (struct obj *,BOOLEAN_P,BOOLEAN_P,XCHAR_P,XCHAR_P)); E boolean FDECL(fire_damage, (struct obj *,BOOLEAN_P,XCHAR_P,XCHAR_P));
E int FDECL(fire_damage_chain, (struct obj *,BOOLEAN_P,BOOLEAN_P,XCHAR_P,XCHAR_P));
E void acid_damage(struct obj *); E void acid_damage(struct obj *);
E int FDECL(water_damage, (struct obj *,const char*,BOOLEAN_P)); E int FDECL(water_damage, (struct obj *,const char*,BOOLEAN_P));
E void FDECL(water_damage_chain, (struct obj *,BOOLEAN_P)); E void FDECL(water_damage_chain, (struct obj *,BOOLEAN_P));

View File

@@ -99,6 +99,9 @@
#define COST_BITE 13 /* start eating food */ #define COST_BITE 13 /* start eating food */
#define COST_OPEN 14 /* open tin */ #define COST_OPEN 14 /* open tin */
#define COST_BRKLCK 15 /* break box/chest's lock */ #define COST_BRKLCK 15 /* break box/chest's lock */
#define COST_RUST 16 /* rust damage */
#define COST_ROT 17 /* rotting attack */
#define COST_CORRODE 18 /* acid damage */
/* bitmask flags for corpse_xname(); /* bitmask flags for corpse_xname();
PFX_THE takes precedence over ARTICLE, NO_PFX takes precedence over both */ PFX_THE takes precedence over ARTICLE, NO_PFX takes precedence over both */

View File

@@ -325,6 +325,19 @@ struct obj {
#define ERODE_ROT 2 #define ERODE_ROT 2
#define ERODE_CORRODE 3 #define ERODE_CORRODE 3
/* erosion flags for erode_obj() */
#define EF_NONE 0
#define EF_GREASE 0x1 /* check for a greased object */
#define EF_DESTROY 0x2 /* potentially destroy the object */
#define EF_VERBOSE 0x4 /* print extra messages */
#define EF_PAY 0x8 /* it's the player's fault */
/* erosion return values for erode_obj(), water_damage() */
#define ER_NOTHING 0 /* nothing happened */
#define ER_GREASED 1 /* protected by grease */
#define ER_DAMAGED 2 /* object was damaged in some way */
#define ER_DESTROYED 3 /* object was destroyed */
/* /*
* Notes for adding new oextra structures: * Notes for adding new oextra structures:
* *

View File

@@ -184,7 +184,7 @@ const char *verb;
newsym(x,y); newsym(x,y);
return TRUE; return TRUE;
} else if (is_lava(x, y)) { } else if (is_lava(x, y)) {
return fire_damage(obj, FALSE, FALSE, x, y); return fire_damage(obj, FALSE, x, y);
} else if (is_pool(x, y)) { } else if (is_pool(x, y)) {
/* Reasonably bulky objects (arbitrary) splash when dropped. /* Reasonably bulky objects (arbitrary) splash when dropped.
* If you're floating above the water even small things make * If you're floating above the water even small things make
@@ -201,7 +201,7 @@ const char *verb;
map_background(x, y, 0); map_background(x, y, 0);
newsym(x, y); newsym(x, y);
} }
return water_damage(obj, NULL, FALSE) == 3; return water_damage(obj, NULL, FALSE) == ER_DESTROYED;
} else if (u.ux == x && u.uy == y && } else if (u.ux == x && u.uy == y &&
(t = t_at(x,y)) != 0 && uteetering_at_seen_pit(t)) { (t = t_at(x,y)) != 0 && uteetering_at_seen_pit(t)) {
if (Blind && !Deaf) if (Blind && !Deaf)

View File

@@ -983,7 +983,8 @@ dokick()
if(!rn2(3)) goto ouch; if(!rn2(3)) goto ouch;
/* make metal boots rust */ /* make metal boots rust */
if(uarmf && rn2(3)) if(uarmf && rn2(3))
if (!water_damage(uarmf, "metal boots", TRUE)) { if (water_damage(uarmf, "metal boots", TRUE) ==
ER_NOTHING) {
Your("boots get wet."); Your("boots get wet.");
/* could cause short-lived fumbling here */ /* could cause short-lived fumbling here */
} }

View File

@@ -402,7 +402,7 @@ register struct obj *obj;
if(in_town(u.ux, u.uy)) if(in_town(u.ux, u.uy))
(void) angry_guards(FALSE); (void) angry_guards(FALSE);
return; return;
} else if (water_damage(obj, NULL, TRUE)) { } else if (water_damage(obj, NULL, TRUE) != ER_NOTHING) {
if (obj->otyp == POT_ACID) { /* Acid and water don't mix */ if (obj->otyp == POT_ACID) { /* Acid and water don't mix */
useup(obj); useup(obj);
return; return;

View File

@@ -1303,7 +1303,7 @@ register struct obj *obj;
dmgtyp = ERODE_BURN; dmgtyp = ERODE_BURN;
else else
return; return;
(void) erode_obj(obj, 0, dmgtyp, TRUE, TRUE); (void) erode_obj(obj, NULL, dmgtyp, EF_GREASE | EF_VERBOSE);
} }
STATIC_OVL void STATIC_OVL void

View File

@@ -502,7 +502,7 @@ static const char * const alteration_verbs[] = {
"cancel", "drain", "uncharge", "unbless", "uncurse", "cancel", "drain", "uncharge", "unbless", "uncurse",
"disenchant", "degrade", "dilute", "erase", "burn", "disenchant", "degrade", "dilute", "erase", "burn",
"neutralize", "destroy", "splatter", "bite", "open", "neutralize", "destroy", "splatter", "bite", "open",
"break the lock on", "break the lock on", "rust", "rot", "tarnish"
}; };
/* possibly bill for an object which the player has just modified */ /* possibly bill for an object which the player has just modified */

View File

@@ -373,8 +373,8 @@ register struct monst *mtmp;
pline("%s burns slightly.", Monnam(mtmp)); pline("%s burns slightly.", Monnam(mtmp));
} }
if (mtmp->mhp > 0) { if (mtmp->mhp > 0) {
(void) fire_damage(mtmp->minvent, FALSE, FALSE, (void) fire_damage_chain(mtmp->minvent, FALSE, FALSE, mtmp->mx,
mtmp->mx, mtmp->my); mtmp->my);
(void) rloc(mtmp, FALSE); (void) rloc(mtmp, FALSE);
return 0; return 0;
} }

View File

@@ -1088,7 +1088,7 @@ const char *objphrase; /* "Your widget glows" or "Steed's saddle glows" */
} else { } else {
/* dipping into uncursed water; carried() check skips steed saddle */ /* dipping into uncursed water; carried() check skips steed saddle */
if (carried(targobj)) { if (carried(targobj)) {
if (water_damage(targobj, 0, TRUE)) if (water_damage(targobj, 0, TRUE) != ER_NOTHING)
res = TRUE; res = TRUE;
} }
} }
@@ -1839,38 +1839,14 @@ dodip()
} }
if (potion->otyp == POT_ACID) { if (potion->otyp == POT_ACID) {
if (erode_obj(obj, 0, ERODE_CORRODE, TRUE, FALSE)) if (erode_obj(obj, 0, ERODE_CORRODE, EF_GREASE) != ER_NOTHING)
goto poof; goto poof;
} }
if (potion->otyp == POT_OIL) { if (potion->otyp == POT_OIL) {
boolean wisx = FALSE; boolean wisx = FALSE;
if (potion->lamplit) { /* burning */ if (potion->lamplit) { /* burning */
int omat = objects[obj->otyp].oc_material; fire_damage(obj, TRUE, u.ux, u.uy);
/* the code here should be merged with fire_damage */
if (catch_lit(obj)) {
/* 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 but %s unharmed.",
Yname2(obj), otense(obj, "seem"), otense(obj, "are"));
} else {
if ((omat == PLASTIC || omat == PAPER) && !obj->oartifact)
obj->oeroded = MAX_ERODE;
pline_The("burning oil %s %s%c",
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 {
obj->oeroded++;
}
}
} else if (potion->cursed) { } else if (potion->cursed) {
pline_The("potion spills and covers your %s with oil.", pline_The("potion spills and covers your %s with oil.",
makeplural(body_part(FINGER))); makeplural(body_part(FINGER)));

View File

@@ -144,7 +144,8 @@ cursed_book(bp)
case 5: case 5:
pline_The("book was coated with contact poison!"); pline_The("book was coated with contact poison!");
if (uarmg) { if (uarmg) {
erode_obj(uarmg, "gloves", ERODE_CORRODE, TRUE, TRUE); erode_obj(uarmg, "gloves", ERODE_CORRODE,
EF_GREASE | EF_VERBOSE);
break; break;
} }
/* temp disable in_use; death should not destroy the book */ /* temp disable in_use; death should not destroy the book */

View File

@@ -55,7 +55,7 @@ struct monst *victim;
int mat_idx; int mat_idx;
if (!victim) return 0; if (!victim) return 0;
#define burn_dmg(obj,descr) erode_obj(obj, descr, ERODE_BURN, TRUE, FALSE) #define burn_dmg(obj,descr) erode_obj(obj, descr, ERODE_BURN, EF_GREASE)
while (1) { while (1) {
switch (rn2(5)) { switch (rn2(5)) {
case 0: case 0:
@@ -101,31 +101,34 @@ struct monst *victim;
#undef burn_dmg #undef burn_dmg
} }
/* Generic erode-item function. Returns TRUE if any change in state /* Generic erode-item function.
* occurred, or if grease protected the item.
* "ostr", if non-null, is an alternate string to print instead of the * "ostr", if non-null, is an alternate string to print instead of the
* object's name. * object's name.
* "check_grease", if FALSE, means that grease is not checked for * "type" is an ERODE_* value for the erosion type
* "print", if set, means to print a message even if no change occurs. * "flags" is an or-ed list of EF_* flags
*
* Returns an erosion return value (ER_*)
*/ */
boolean int
erode_obj(otmp, ostr, type, check_grease, print) erode_obj(otmp, ostr, type, ef_flags)
register struct obj *otmp; register struct obj *otmp;
register const char *ostr; register const char *ostr;
int type; int type;
boolean check_grease; int ef_flags;
boolean print;
{ {
static NEARDATA const char * const action[] = { "smoulder", "rust", "rot", "corrode" }; static NEARDATA const char * const action[] = { "smoulder", "rust", "rot", "corrode" };
static NEARDATA const char * const msg[] = { "burnt", "rusted", "rotten", "corroded" }; static NEARDATA const char * const msg[] = { "burnt", "rusted", "rotten", "corroded" };
boolean vulnerable = FALSE; boolean vulnerable = FALSE;
boolean is_primary = TRUE; boolean is_primary = TRUE;
boolean check_grease = ef_flags & EF_GREASE;
boolean print = ef_flags & EF_VERBOSE;
int erosion; int erosion;
struct monst *victim; struct monst *victim;
boolean vismon; boolean vismon;
boolean visobj; boolean visobj;
int cost_type;
if (!otmp) return(FALSE); if (!otmp) return ER_NOTHING;
victim = carried(otmp) ? &youmonst : mcarried(otmp) ? victim = carried(otmp) ? &youmonst : mcarried(otmp) ?
otmp->ocarry : NULL; otmp->ocarry : NULL;
@@ -137,22 +140,26 @@ boolean print;
case ERODE_BURN: case ERODE_BURN:
vulnerable = is_flammable(otmp); vulnerable = is_flammable(otmp);
check_grease = FALSE; check_grease = FALSE;
cost_type = COST_BURN;
break; break;
case ERODE_RUST: case ERODE_RUST:
vulnerable = is_rustprone(otmp); vulnerable = is_rustprone(otmp);
cost_type = COST_RUST;
break; break;
case ERODE_ROT: case ERODE_ROT:
vulnerable = is_rottable(otmp); vulnerable = is_rottable(otmp);
check_grease = FALSE; check_grease = FALSE;
is_primary = FALSE; is_primary = FALSE;
cost_type = COST_ROT;
break; break;
case ERODE_CORRODE: case ERODE_CORRODE:
vulnerable = is_corrodeable(otmp); vulnerable = is_corrodeable(otmp);
is_primary = FALSE; is_primary = FALSE;
cost_type = COST_CORRODE;
break; break;
default: default:
impossible("Invalid erosion type in erode_obj"); impossible("Invalid erosion type in erode_obj");
return FALSE; return ER_NOTHING;
} }
erosion = is_primary ? otmp->oeroded : otmp->oeroded2; erosion = is_primary ? otmp->oeroded : otmp->oeroded2;
@@ -161,7 +168,7 @@ boolean print;
if (check_grease && otmp->greased) { if (check_grease && otmp->greased) {
grease_protect(otmp, ostr, victim); grease_protect(otmp, ostr, victim);
return TRUE; return ER_GREASED;
} else if (!vulnerable || (otmp->oerodeproof && otmp->rknown)) { } else if (!vulnerable || (otmp->oerodeproof && otmp->rknown)) {
if (print && flags.verbose) { if (print && flags.verbose) {
if (victim == &youmonst) if (victim == &youmonst)
@@ -170,7 +177,7 @@ boolean print;
pline("%s %s %s not affected.", s_suffix(Monnam(victim)), pline("%s %s %s not affected.", s_suffix(Monnam(victim)),
ostr, vtense(ostr, "are")); ostr, vtense(ostr, "are"));
} }
return FALSE; return ER_NOTHING;
} else if (otmp->oerodeproof || (otmp->blessed && !rnl(4))) { } else if (otmp->oerodeproof || (otmp->blessed && !rnl(4))) {
if (flags.verbose && (print || otmp->oerodeproof)) { if (flags.verbose && (print || otmp->oerodeproof)) {
if (victim == &youmonst) if (victim == &youmonst)
@@ -188,9 +195,13 @@ boolean print;
* is blessed, it still shows some minor signs of wear, and * is blessed, it still shows some minor signs of wear, and
* the hero can distinguish this from an object that is * the hero can distinguish this from an object that is
* actually proof against damage. */ * actually proof against damage. */
if (otmp->oerodeproof) if (otmp->oerodeproof) {
otmp->rknown = TRUE; otmp->rknown = TRUE;
return FALSE; if (victim == &youmonst)
update_inventory();
}
return ER_NOTHING;
} else if (erosion < MAX_ERODE) { } else if (erosion < MAX_ERODE) {
const char *adverb = (erosion + 1 == MAX_ERODE) ? const char *adverb = (erosion + 1 == MAX_ERODE) ?
" completely" : erosion ? " further" : ""; " completely" : erosion ? " further" : "";
@@ -198,19 +209,39 @@ boolean print;
if (victim == &youmonst) if (victim == &youmonst)
Your("%s %s%s!", ostr, vtense(ostr, action[type]), adverb); Your("%s %s%s!", ostr, vtense(ostr, action[type]), adverb);
else if (vismon) else if (vismon)
pline("%s's %s %s%s!", Monnam(victim), ostr, pline("%s %s %s%s!", s_suffix(Monnam(victim)), ostr,
vtense(ostr, action[type]), adverb); vtense(ostr, action[type]), adverb);
else if (visobj) else if (visobj)
pline("The %s %s%s!", ostr, vtense(ostr, action[type]), adverb); pline("The %s %s%s!", ostr, vtense(ostr, action[type]), adverb);
if (ef_flags & EF_PAY)
costly_alteration(otmp, cost_type);
if (is_primary) if (is_primary)
otmp->oeroded++; otmp->oeroded++;
else else
otmp->oeroded2++; otmp->oeroded2++;
update_inventory(); if (victim == &youmonst)
return TRUE; update_inventory();
} else {
return ER_DAMAGED;
} else if (ef_flags & EF_DESTROY) {
if (victim == &youmonst)
Your("%s %s away!", ostr, vtense(ostr, action[type]));
else if (vismon)
pline("%s %s %s away!", s_suffix(Monnam(victim)), ostr,
vtense(ostr, action[type]));
else if (visobj)
pline("The %s %s away!", ostr, vtense(ostr, action[type]));
if (ef_flags & EF_PAY)
costly_alteration(otmp, cost_type);
setnotworn(otmp);
delobj(otmp);
return ER_DESTROYED;
} else {
if (flags.verbose && print) { if (flags.verbose && print) {
if (victim == &youmonst) if (victim == &youmonst)
Your("%s %s completely %s.", ostr, Your("%s %s completely %s.", ostr,
@@ -224,7 +255,7 @@ boolean print;
pline("The %s %s completely %s.", ostr, pline("The %s %s completely %s.", ostr,
vtense(ostr, "look"), msg[type]); vtense(ostr, "look"), msg[type]);
} }
return FALSE; return ER_NOTHING;
} }
} }
@@ -952,7 +983,7 @@ unsigned trflags;
case 1: case 1:
pline("%s your left %s!", A_gush_of_water_hits, pline("%s your left %s!", A_gush_of_water_hits,
body_part(ARM)); body_part(ARM));
if (water_damage(uarms, "shield", TRUE)) if (water_damage(uarms, "shield", TRUE) != ER_NOTHING)
break; break;
if (u.twoweap || (uwep && bimanual(uwep))) if (u.twoweap || (uwep && bimanual(uwep)))
(void) water_damage(u.twoweap ? uswapwep : uwep, 0, (void) water_damage(u.twoweap ? uswapwep : uwep, 0,
@@ -2097,7 +2128,7 @@ register struct monst *mtmp;
pline("%s %s's left %s!", A_gush_of_water_hits, pline("%s %s's left %s!", A_gush_of_water_hits,
mon_nam(mtmp), mbodypart(mtmp, ARM)); mon_nam(mtmp), mbodypart(mtmp, ARM));
target = which_armor(mtmp, W_ARMS); target = which_armor(mtmp, W_ARMS);
if (water_damage(target, "shield", TRUE)) if (water_damage(target, "shield", TRUE) != ER_NOTHING)
break; break;
target = MON_WEP(mtmp); target = MON_WEP(mtmp);
if (target && bimanual(target)) if (target && bimanual(target))
@@ -2972,104 +3003,118 @@ domagictrap()
} }
} }
/* /* Set an item on fire.
* Scrolls, spellbooks, potions, and flammable items * "force" means not to roll a luck-based protection check for the
* may get affected by the fire. * item.
* "x" and "y" are the coordinates to dump the contents of a
* container, if it burns up.
* *
* Return number of objects destroyed. --ALI * Return whether the object was destroyed.
*/ */
int boolean
fire_damage(chain, force, here, x, y) fire_damage(obj, force, x, y)
struct obj *chain; struct obj *obj;
boolean force, here; boolean force;
xchar x, y; xchar x, y;
{ {
int chance; int chance;
struct obj *obj, *otmp, *nobj, *ncobj; struct obj *otmp, *ncobj;
int retval = 0; int retval = 0;
int in_sight = !Blind && couldsee(x, y); /* Don't care if it's lit */ int in_sight = !Blind && couldsee(x, y); /* Don't care if it's lit */
int dindx; int dindx;
/* object might light in a controlled manner */
if (catch_lit(obj))
return FALSE;
if (Is_container(obj)) {
switch (obj->otyp) {
case ICE_BOX:
return FALSE; /* Immune */
case CHEST:
chance = 40;
break;
case LARGE_BOX:
chance = 30;
break;
default:
chance = 20;
break;
}
if ((!force && (Luck + 5) > rn2(chance)) ||
(is_flammable(obj) && obj->oerodeproof))
return FALSE;
/* Container is burnt up - dump contents out */
if (in_sight) pline("%s catches fire and burns.", Yname2(obj));
if (Has_contents(obj)) {
if (in_sight) pline("Its contents fall out.");
for (otmp = obj->cobj; otmp; otmp = ncobj) {
ncobj = otmp->nobj;
obj_extract_self(otmp);
if (!flooreffects(otmp, x, y, ""))
place_object(otmp, x, y);
}
}
setnotworn(obj);
delobj(obj);
return TRUE;
} else if (!force && (Luck + 5) > rn2(20)) {
/* chance per item of sustaining damage:
* max luck (Luck==13): 10%
* avg luck (Luck==0): 75%
* awful luck (Luck<-4): 100%
*/
return FALSE;
} else if (obj->oclass == SCROLL_CLASS || obj->oclass == SPBOOK_CLASS) {
if (obj->otyp == SCR_FIRE || obj->otyp == SPE_FIREBALL)
return FALSE;
if (obj->otyp == SPE_BOOK_OF_THE_DEAD) {
if (in_sight) pline("Smoke rises from %s.", the(xname(obj)));
return FALSE;
}
dindx = (obj->oclass == SCROLL_CLASS) ? 3 : 4;
if (in_sight)
pline("%s %s.", Yname2(obj),
destroy_strings[dindx][(obj->quan > 1L)]);
setnotworn(obj);
delobj(obj);
return TRUE;
} else if (obj->oclass == POTION_CLASS) {
dindx = (obj->otyp != POT_OIL) ? 1 : 2;
if (in_sight)
pline("%s %s.", Yname2(obj),
destroy_strings[dindx][(obj->quan > 1L)]);
setnotworn(obj);
delobj(obj);
return TRUE;
} else if (erode_obj(obj, NULL, ERODE_BURN, EF_DESTROY) == ER_DESTROYED) {
return TRUE;
}
return FALSE;
}
/*
* Apply fire_damage() to an entire chain.
*
* Return number of objects destroyed. --ALI
*/
int
fire_damage_chain(chain, force, here, x, y)
struct obj *chain;
boolean force, here;
xchar x, y;
{
struct obj *obj, *nobj;
int num = 0;
for (obj = chain; obj; obj = nobj) { for (obj = chain; obj; obj = nobj) {
nobj = here ? obj->nexthere : obj->nobj; nobj = here ? obj->nexthere : obj->nobj;
if (fire_damage(obj, force, x, y))
/* object might light in a controlled manner */ ++num;
if (catch_lit(obj))
continue;
if (Is_container(obj)) {
switch (obj->otyp) {
case ICE_BOX:
continue; /* Immune */
/*NOTREACHED*/
break;
case CHEST:
chance = 40;
break;
case LARGE_BOX:
chance = 30;
break;
default:
chance = 20;
break;
}
if ((!force && (Luck + 5) > rn2(chance)) ||
(is_flammable(obj) && obj->oerodeproof))
continue;
/* Container is burnt up - dump contents out */
if (in_sight) pline("%s catches fire and burns.", Yname2(obj));
if (Has_contents(obj)) {
if (in_sight) pline("Its contents fall out.");
for (otmp = obj->cobj; otmp; otmp = ncobj) {
ncobj = otmp->nobj;
obj_extract_self(otmp);
if (!flooreffects(otmp, x, y, ""))
place_object(otmp, x, y);
}
}
delobj(obj);
retval++;
} else if (!force && (Luck + 5) > rn2(20)) {
/* chance per item of sustaining damage:
* max luck (Luck==13): 10%
* avg luck (Luck==0): 75%
* awful luck (Luck<-4): 100%
*/
continue;
} else if (obj->oclass == SCROLL_CLASS || obj->oclass == SPBOOK_CLASS) {
if (obj->otyp == SCR_FIRE || obj->otyp == SPE_FIREBALL)
continue;
if (obj->otyp == SPE_BOOK_OF_THE_DEAD) {
if (in_sight) pline("Smoke rises from %s.", the(xname(obj)));
continue;
}
dindx = (obj->oclass == SCROLL_CLASS) ? 3 : 4;
if (in_sight)
pline("%s %s.", Yname2(obj),
destroy_strings[dindx][(obj->quan > 1L)]);
delobj(obj);
retval++;
} else if (obj->oclass == POTION_CLASS) {
dindx = (obj->otyp != POT_OIL) ? 1 : 2;
if (in_sight)
pline("%s %s.", Yname2(obj),
destroy_strings[dindx][(obj->quan > 1L)]);
delobj(obj);
retval++;
} else if (is_flammable(obj) && obj->oeroded < MAX_ERODE &&
!(obj->oerodeproof || (obj->blessed && !rnl(4)))) {
if (in_sight) {
pline("%s %s%s.", Yname2(obj), otense(obj, "burn"),
obj->oeroded+1 == MAX_ERODE ? " completely" :
obj->oeroded ? " further" : "");
}
obj->oeroded++;
}
} }
if (retval && !in_sight) if (num && (Blind && !couldsee(x, y)))
You("smell smoke."); You("smell smoke.");
return retval; return num;
} }
void void
@@ -3101,14 +3146,14 @@ struct obj *obj;
obj->spe = 0; obj->spe = 0;
obj->dknown = 0; obj->dknown = 0;
} else } else
erode_obj(obj, NULL, ERODE_CORRODE, TRUE, TRUE); erode_obj(obj, NULL, ERODE_CORRODE, EF_GREASE | EF_VERBOSE);
} }
/* returns: /* Get an object wet and damage it appropriately.
* 0 if obj is unaffected * "ostr", if present, is used instead of the object name in some
* 1 if obj is protected by grease * messages.
* 2 if obj is changed but survived * "force" means not to roll luck to protect some objects.
* 3 if obj is destroyed * Returns an erosion return value (ER_*)
*/ */
int int
water_damage(obj, ostr, force) water_damage(obj, ostr, force)
@@ -3119,25 +3164,25 @@ boolean force;
boolean loose_obj = (obj && obj->where == OBJ_FREE), exploded = FALSE; boolean loose_obj = (obj && obj->where == OBJ_FREE), exploded = FALSE;
if (snuff_lit(obj)) if (snuff_lit(obj))
return 2; return ER_DAMAGED;
if(obj->otyp == CAN_OF_GREASE && obj->spe > 0) { if(obj->otyp == CAN_OF_GREASE && obj->spe > 0) {
return 0; return ER_NOTHING;
} else if(obj->greased) { } else if(obj->greased) {
if (!rn2(2)) obj->greased = 0; if (!rn2(2)) obj->greased = 0;
if (carried(obj)) update_inventory(); if (carried(obj)) update_inventory();
return 1; return ER_GREASED;
} else if(Is_container(obj) && !Is_box(obj) && } else if(Is_container(obj) && !Is_box(obj) &&
(obj->otyp != OILSKIN_SACK || (obj->cursed && !rn2(3)))) { (obj->otyp != OILSKIN_SACK || (obj->cursed && !rn2(3)))) {
water_damage_chain(obj->cobj, FALSE); water_damage_chain(obj->cobj, FALSE);
return 0; return ER_NOTHING;
} else if (!force && (Luck + 5) > rn2(20)) { } else if (!force && (Luck + 5) > rn2(20)) {
/* chance per item of sustaining damage: /* chance per item of sustaining damage:
* max luck: 10% * max luck: 10%
* avg luck (Luck==0): 75% * avg luck (Luck==0): 75%
* awful luck (Luck<-4): 100% * awful luck (Luck<-4): 100%
*/ */
return 0; return ER_NOTHING;
} else if (obj->oclass == SCROLL_CLASS) { } else if (obj->oclass == SCROLL_CLASS) {
#ifdef MAIL #ifdef MAIL
if (obj->otyp == SCR_MAIL) return 0; if (obj->otyp == SCR_MAIL) return 0;
@@ -3147,7 +3192,7 @@ boolean force;
obj->spe = 0; obj->spe = 0;
if (carried(obj)) if (carried(obj))
update_inventory(); update_inventory();
return 2; return ER_DAMAGED;
} else if (obj->oclass == SPBOOK_CLASS) { } else if (obj->oclass == SPBOOK_CLASS) {
if (obj->otyp == SPE_BOOK_OF_THE_DEAD) { if (obj->otyp == SPE_BOOK_OF_THE_DEAD) {
pline("Steam rises from %s.", the(xname(obj))); pline("Steam rises from %s.", the(xname(obj)));
@@ -3157,7 +3202,7 @@ boolean force;
obj->dknown = 0; obj->dknown = 0;
if (carried(obj)) if (carried(obj))
update_inventory(); update_inventory();
return 2; return ER_DAMAGED;
} else if (obj->oclass == POTION_CLASS) { } else if (obj->oclass == POTION_CLASS) {
if (obj->otyp == POT_ACID) { if (obj->otyp == POT_ACID) {
char *bufp, buf[BUFSZ]; char *bufp, buf[BUFSZ];
@@ -3177,10 +3222,11 @@ boolean force;
obj_extract_self() takes care of this; obj_extract_self() takes care of this;
for loose_obj, obj should always equal for loose_obj, obj should always equal
*objp and otmp should always be null] */ *objp and otmp should always be null] */
setnotworn(obj);
delobj(obj); delobj(obj);
if (update) if (update)
update_inventory(); update_inventory();
return 3; return ER_DESTROYED;
} else if (obj->odiluted) { } else if (obj->odiluted) {
obj->otyp = POT_WATER; obj->otyp = POT_WATER;
obj->dknown = 0; obj->dknown = 0;
@@ -3188,17 +3234,17 @@ boolean force;
obj->odiluted = 0; obj->odiluted = 0;
if (carried(obj)) if (carried(obj))
update_inventory(); update_inventory();
return 2; return ER_DAMAGED;
} else if (obj->otyp != POT_WATER) { } else if (obj->otyp != POT_WATER) {
obj->odiluted++; obj->odiluted++;
if (carried(obj)) if (carried(obj))
update_inventory(); update_inventory();
return 2; return ER_DAMAGED;
} }
} else { } else {
return erode_obj(obj, ostr, ERODE_RUST, FALSE, FALSE) ? 2 : 0; return erode_obj(obj, ostr, ERODE_RUST, EF_NONE);
} }
return 0; return ER_NOTHING;
} }
void void

View File

@@ -47,34 +47,38 @@ int hurt;
switch(rn2(5)) { switch(rn2(5)) {
case 0: case 0:
target = which_armor(mdef, W_ARMH); target = which_armor(mdef, W_ARMH);
if (!target || !erode_obj(target, xname(target), hurt, TRUE, FALSE)) if (!target ||
erode_obj(target, xname(target), hurt, EF_GREASE) == ER_NOTHING)
continue; continue;
break; break;
case 1: case 1:
target = which_armor(mdef, W_ARMC); target = which_armor(mdef, W_ARMC);
if (target) { if (target) {
(void)erode_obj(target, xname(target), hurt, TRUE, TRUE); (void)erode_obj(target, xname(target), hurt, EF_GREASE | EF_VERBOSE);
break; break;
} }
if ((target = which_armor(mdef, W_ARM)) != (struct obj *)0) { if ((target = which_armor(mdef, W_ARM)) != (struct obj *)0) {
(void)erode_obj(target, xname(target), hurt, TRUE, TRUE); (void)erode_obj(target, xname(target), hurt, EF_GREASE | EF_VERBOSE);
} else if ((target = which_armor(mdef, W_ARMU)) != (struct obj *)0) { } else if ((target = which_armor(mdef, W_ARMU)) != (struct obj *)0) {
(void)erode_obj(target, xname(target), hurt, TRUE, TRUE); (void)erode_obj(target, xname(target), hurt, EF_GREASE | EF_VERBOSE);
} }
break; break;
case 2: case 2:
target = which_armor(mdef, W_ARMS); target = which_armor(mdef, W_ARMS);
if (!target || !erode_obj(target, xname(target), hurt, TRUE, FALSE)) if (!target ||
erode_obj(target, xname(target), hurt, EF_GREASE) == ER_NOTHING)
continue; continue;
break; break;
case 3: case 3:
target = which_armor(mdef, W_ARMG); target = which_armor(mdef, W_ARMG);
if (!target || !erode_obj(target, xname(target), hurt, TRUE, FALSE)) if (!target ||
erode_obj(target, xname(target), hurt, EF_GREASE) == ER_NOTHING)
continue; continue;
break; break;
case 4: case 4:
target = which_armor(mdef, W_ARMF); target = which_armor(mdef, W_ARMF);
if (!target || !erode_obj(target, xname(target), hurt, TRUE, FALSE)) if (!target ||
erode_obj(target, xname(target), hurt, EF_GREASE) == ER_NOTHING)
continue; continue;
break; break;
} }
@@ -2222,7 +2226,8 @@ boolean wep_was_destroyed;
if(mhit && !mon->mcan) { if(mhit && !mon->mcan) {
if (aatyp == AT_KICK) { if (aatyp == AT_KICK) {
if (uarmf && !rn2(6)) if (uarmf && !rn2(6))
(void)erode_obj(uarmf, xname(uarmf), ERODE_BURN, TRUE, TRUE); (void)erode_obj(uarmf, xname(uarmf), ERODE_BURN,
EF_GREASE | EF_VERBOSE);
} else if (aatyp == AT_WEAP || aatyp == AT_CLAW || } else if (aatyp == AT_WEAP || aatyp == AT_CLAW ||
aatyp == AT_MAGC || aatyp == AT_TUCH) aatyp == AT_MAGC || aatyp == AT_TUCH)
passive_obj(mon, (struct obj*)0, &(ptr->mattk[i])); passive_obj(mon, (struct obj*)0, &(ptr->mattk[i]));
@@ -2242,7 +2247,8 @@ boolean wep_was_destroyed;
if (mhit) { if (mhit) {
if (aatyp == AT_KICK) { if (aatyp == AT_KICK) {
if (uarmf && !rn2(6)) if (uarmf && !rn2(6))
(void)erode_obj(uarmf, xname(uarmf), ERODE_CORRODE, TRUE, TRUE); (void)erode_obj(uarmf, xname(uarmf), ERODE_CORRODE,
EF_GREASE | EF_VERBOSE);
} else if (aatyp == AT_WEAP || aatyp == AT_CLAW || } else if (aatyp == AT_WEAP || aatyp == AT_CLAW ||
aatyp == AT_MAGC || aatyp == AT_TUCH) aatyp == AT_MAGC || aatyp == AT_TUCH)
passive_obj(mon, (struct obj*)0, &(ptr->mattk[i])); passive_obj(mon, (struct obj*)0, &(ptr->mattk[i]));
@@ -2275,7 +2281,8 @@ boolean wep_was_destroyed;
if(mhit && !mon->mcan) { if(mhit && !mon->mcan) {
if (aatyp == AT_KICK) { if (aatyp == AT_KICK) {
if (uarmf) if (uarmf)
(void)erode_obj(uarmf, xname(uarmf), ERODE_RUST, TRUE, TRUE); (void)erode_obj(uarmf, xname(uarmf), ERODE_RUST,
EF_GREASE | EF_VERBOSE);
} else if (aatyp == AT_WEAP || aatyp == AT_CLAW || } else if (aatyp == AT_WEAP || aatyp == AT_CLAW ||
aatyp == AT_MAGC || aatyp == AT_TUCH) aatyp == AT_MAGC || aatyp == AT_TUCH)
passive_obj(mon, (struct obj*)0, &(ptr->mattk[i])); passive_obj(mon, (struct obj*)0, &(ptr->mattk[i]));
@@ -2285,7 +2292,8 @@ boolean wep_was_destroyed;
if(mhit && !mon->mcan) { if(mhit && !mon->mcan) {
if (aatyp == AT_KICK) { if (aatyp == AT_KICK) {
if (uarmf) if (uarmf)
(void)erode_obj(uarmf, xname(uarmf), ERODE_CORRODE, TRUE, TRUE); (void)erode_obj(uarmf, xname(uarmf), ERODE_CORRODE,
EF_GREASE | EF_VERBOSE);
} else if (aatyp == AT_WEAP || aatyp == AT_CLAW || } else if (aatyp == AT_WEAP || aatyp == AT_CLAW ||
aatyp == AT_MAGC || aatyp == AT_TUCH) aatyp == AT_MAGC || aatyp == AT_TUCH)
passive_obj(mon, (struct obj*)0, &(ptr->mattk[i])); passive_obj(mon, (struct obj*)0, &(ptr->mattk[i]));
@@ -2446,22 +2454,22 @@ struct attack *mattk; /* null means we find one internally */
case AD_FIRE: case AD_FIRE:
if(!rn2(6) && !mon->mcan) { if(!rn2(6) && !mon->mcan) {
(void) erode_obj(obj, 0, ERODE_BURN, FALSE, FALSE); (void) erode_obj(obj, NULL, ERODE_BURN, EF_NONE);
} }
break; break;
case AD_ACID: case AD_ACID:
if(!rn2(6)) { if(!rn2(6)) {
(void) erode_obj(obj, 0, ERODE_CORRODE, FALSE, FALSE); (void) erode_obj(obj, NULL, ERODE_CORRODE, EF_NONE);
} }
break; break;
case AD_RUST: case AD_RUST:
if(!mon->mcan) { if(!mon->mcan) {
(void) erode_obj(obj, 0, ERODE_RUST, FALSE, FALSE); (void) erode_obj(obj, NULL, ERODE_RUST, EF_NONE);
} }
break; break;
case AD_CORR: case AD_CORR:
if(!mon->mcan) { if(!mon->mcan) {
(void) erode_obj(obj, 0, ERODE_CORRODE, FALSE, FALSE); (void) erode_obj(obj, NULL, ERODE_CORRODE, EF_NONE);
} }
break; break;
case AD_ENCH: case AD_ENCH: