revisit destroy_armor()

add a static function maybe_destroy_armor() to replace
the DESTROY_ARM() macro.

The DESTROY_ARM() macro expanded to legal code, but did include
side-effects of making assignments to local variable otmp (not an
argument to the macro), referenced local variable atmp (not an
argument to the macro), and sometimes setting the in_use field
on the impacted armor obj.

The assignment statements within the if (...) caused some compilers
and code analyzers to complain and suggest that perhaps
'=' should have been '==', which was incorrect.

The maybe_destroy_armor() function provides the
caller with information about whether the armor resisted,
so that appropriate action can be taken within the caller.
This commit is contained in:
nhmall
2023-12-28 19:17:43 -05:00
parent 36c5843103
commit 719919b16a

View File

@@ -49,6 +49,9 @@ static int puton_ok(struct obj *);
static int remove_ok(struct obj *);
static int wear_ok(struct obj *);
static int takeoff_ok(struct obj *);
/* maybe_destroy_armor() may return NULL */
static struct obj *maybe_destroy_armor(struct obj *, struct obj *,
boolean *) NONNULLARG3;
/* plural "fingers" or optionally "gloves" */
const char *
@@ -3035,28 +3038,42 @@ wornarm_destroyed(struct obj *wornarm)
}
}
/*
* returns impacted armor with its in_use bit set,
* or Null. *resisted is updated to reflect whether
* it resisted or not */
static struct obj *
maybe_destroy_armor(struct obj *armor, struct obj *atmp, boolean *resisted)
{
if ((armor != 0) && (!atmp || atmp == armor)
&& ((*resisted = obj_resists(armor, 0, 90)) == FALSE)) {
armor->in_use = 1;
return armor;
}
return (struct obj *) 0;
}
/* hit by destroy armor scroll/black dragon breath/monster spell */
int
destroy_arm(struct obj *atmp)
{
struct obj *otmp;
boolean losing_gloves = FALSE;
struct obj *otmp = (struct obj *) 0;
boolean losing_gloves = FALSE, resisted = FALSE,
resistedc = FALSE, resistedsuit = FALSE;
/*
* Note: if there were any artifact cloaks, the 90% chance of
* resistance here means that the cloak could survive and then
* the suit or shirt underneath could be destroyed. Likewise for
* artifact suit over a shirt. That would be a bug. Since there
* aren't any, we'll just look the other way.
* Note: if the cloak resisted, then the suit or shirt underneath
* wouldn't be impacted either. Likewise, if the suit resisted,
* the shirt underneath wouldn't be impacted. Since there are
* no artifact cloaks or suits right now, this is unlikely
* to come into effect, but should it should behave appropriately.
*/
#define DESTROY_ARM(o) \
(((otmp = (o)) != 0 && (!atmp || atmp == otmp) \
&& !obj_resists(otmp, 0, 90)) ? (otmp->in_use = 1) : 0)
if (DESTROY_ARM(uarmc)) {
if ((otmp = maybe_destroy_armor(uarmc, atmp, &resistedc)) != 0) {
urgent_pline("Your %s crumbles and turns to dust!",
/* cloak/robe/apron/smock (ID'd apron)/wrapping */
cloak_simple_name(otmp));
} else if (DESTROY_ARM(uarm)) {
} else if (!resistedc
&& (otmp = maybe_destroy_armor(uarm, atmp, &resistedsuit)) != 0) {
const char *suit = suit_simple_name(otmp);
/* for gold DSM, we don't want Armor_gone() to report that it
@@ -3067,25 +3084,24 @@ destroy_arm(struct obj *atmp)
/* suit might be "dragon scales" so vtense() is needed */
suit, vtense(suit, "turn"), vtense(suit, "fall"),
surface(u.ux, u.uy));
} else if (DESTROY_ARM(uarmu)) {
} else if (!resistedc && !resistedsuit
&& (otmp = maybe_destroy_armor(uarmu, atmp, &resisted)) != 0) {
urgent_pline("Your %s crumbles into tiny threads and falls apart!",
shirt_simple_name(otmp)); /* always "shirt" */
} else if (DESTROY_ARM(uarmh)) {
} else if ((otmp = maybe_destroy_armor(uarmh, atmp, &resisted)) != 0) {
urgent_pline("Your %s turns to dust and is blown away!",
helm_simple_name(otmp)); /* "helm" or "hat" */
} else if (DESTROY_ARM(uarmg)) {
} else if ((otmp = maybe_destroy_armor(uarmg, atmp, &resisted)) != 0) {
urgent_pline("Your %s vanish!", gloves_simple_name(otmp));
losing_gloves = TRUE;
} else if (DESTROY_ARM(uarmf)) {
} else if ((otmp = maybe_destroy_armor(uarmf, atmp, &resisted)) != 0) {
urgent_pline("Your %s disintegrate!", boots_simple_name(otmp));
} else if (DESTROY_ARM(uarms)) {
} else if ((otmp = maybe_destroy_armor(uarms, atmp, &resisted)) != 0) {
urgent_pline("Your %s crumbles away!", shield_simple_name(otmp));
} else {
return 0; /* could not destroy anything */
}
#undef DESTROY_ARM
/* cancel_don() if applicable, Cloak_off()/Armor_off()/&c, and useup() */
wornarm_destroyed(otmp);
/* glove loss means wielded weapon will be touched */