Amulet_on() & Amulet_off()
Fix a FIXME in Amulet_off() for removing an amulet of magical breathing when within a poison gas cloud. Redo message sequencing for both Amulet_on() and Amulet_off(). Use up an amulet of change if put on while the Unchanging attribute is active (via #wizintrinsic) instead of wearing it with no effect. Don't discover amulet of strangulation if put on while already Strangled (via #wizintrinsic).
This commit is contained in:
180
src/do_wear.c
180
src/do_wear.c
@@ -30,7 +30,7 @@ staticfn int Gloves_on(void);
|
||||
staticfn int Shield_on(void);
|
||||
staticfn int Shirt_on(void);
|
||||
staticfn void dragon_armor_handling(struct obj *, boolean, boolean);
|
||||
staticfn void Amulet_on(void);
|
||||
staticfn void Amulet_on(struct obj *) NONNULLARG1;
|
||||
staticfn void learnring(struct obj *, boolean);
|
||||
staticfn void adjust_attrib(struct obj *, int, int);
|
||||
staticfn void Ring_off_or_gone(struct obj *, boolean);
|
||||
@@ -74,6 +74,15 @@ off_msg(struct obj *otmp)
|
||||
staticfn void
|
||||
on_msg(struct obj *otmp)
|
||||
{
|
||||
/* on_msg() for rings and amulets just shows add-to-invent feedback
|
||||
[after caller calls setworn(), for suffix: "(on {left|right} hand)"
|
||||
or "(being worn)"]; eyewear too unless giving verbose message below */
|
||||
if ((otmp->owornmask & (W_RING | W_AMUL)) != 0L
|
||||
|| ((otmp->owornmask & W_TOOL) != 0L && !flags.verbose)) {
|
||||
prinv((char *) NULL, otmp, 0L);
|
||||
return;
|
||||
}
|
||||
|
||||
if (flags.verbose) {
|
||||
char how[BUFSZ];
|
||||
/* call xname() before obj_is_pname(); formatting obj's name
|
||||
@@ -925,16 +934,13 @@ Armor_gone(void)
|
||||
}
|
||||
|
||||
staticfn void
|
||||
Amulet_on(void)
|
||||
Amulet_on(struct obj *amul)
|
||||
{
|
||||
/* make sure amulet isn't wielded; can't use remove_worn_item()
|
||||
here because it has already been set worn in amulet slot */
|
||||
if (uamul == uwep)
|
||||
setuwep((struct obj *) 0);
|
||||
else if (uamul == uswapwep)
|
||||
setuswapwep((struct obj *) 0);
|
||||
else if (uamul == uquiver)
|
||||
setuqwep((struct obj *) 0);
|
||||
boolean on_msg_done = FALSE;
|
||||
|
||||
/* make sure amulet isn't wielded/alt-wielded/quivered, before wearing */
|
||||
remove_worn_item(amul, FALSE);
|
||||
setworn(amul, W_AMUL);
|
||||
|
||||
switch (uamul->otyp) {
|
||||
case AMULET_OF_ESP:
|
||||
@@ -952,8 +958,10 @@ Amulet_on(void)
|
||||
was_in_poison_gas = region_danger();
|
||||
EMagical_breathing |= W_AMUL;
|
||||
if (was_in_poison_gas) {
|
||||
You("are no longer bothered by the poison gas.");
|
||||
makeknown(AMULET_OF_MAGICAL_BREATHING);
|
||||
on_msg(uamul);
|
||||
on_msg_done = TRUE;
|
||||
You("are no longer bothered by the poison gas.");
|
||||
}
|
||||
/* no need to check for becoming able to breathe underwater;
|
||||
if we are underwater, we already can or we would have drowned */
|
||||
@@ -964,46 +972,58 @@ Amulet_on(void)
|
||||
make_slimed(0L, (char *) 0);
|
||||
break;
|
||||
case AMULET_OF_CHANGE: {
|
||||
boolean call_it = FALSE;
|
||||
int new_sex, orig_sex = poly_gender();
|
||||
|
||||
if (Unchanging)
|
||||
break;
|
||||
change_sex();
|
||||
/* in normal play it's not possible to put on an amulet of change
|
||||
while already wearing an amulet of unchanging, but in wizard
|
||||
mode the Unchanging attribute can be set via #wizintrinsic */
|
||||
if (!Unchanging)
|
||||
change_sex();
|
||||
|
||||
new_sex = poly_gender();
|
||||
if (new_sex != orig_sex)
|
||||
makeknown(AMULET_OF_CHANGE);
|
||||
on_msg(uamul); /* show 'z - amulet of change (being worn)' */
|
||||
on_msg_done = TRUE;
|
||||
|
||||
/* Don't use same message as polymorph */
|
||||
if (new_sex != orig_sex) {
|
||||
makeknown(AMULET_OF_CHANGE);
|
||||
newsym(u.ux, u.uy); /* glyphmon flag and tile have changed */
|
||||
disp.botl = TRUE; /* role name or rank title might have changed */
|
||||
You("are suddenly very %s!",
|
||||
flags.female ? "feminine" : "masculine");
|
||||
disp.botl = TRUE;
|
||||
newsym(u.ux, u.uy); /* glyphmon flag and tile may have gone
|
||||
* from male to female or vice versa */
|
||||
} else {
|
||||
/* already polymorphed into single-gender monster; only
|
||||
changed the character's base sex */
|
||||
You("don't feel like yourself.");
|
||||
/* checking dknown is redundant--amulets always have dknown set */
|
||||
call_it = (uamul->dknown != 0);
|
||||
}
|
||||
livelog_newform(FALSE, orig_sex, new_sex);
|
||||
pline_The("amulet disintegrates!");
|
||||
if (orig_sex == poly_gender() && uamul->dknown)
|
||||
if (call_it)
|
||||
trycall(uamul);
|
||||
useup(uamul);
|
||||
break;
|
||||
}
|
||||
case AMULET_OF_STRANGULATION:
|
||||
if (can_be_strangled(&gy.youmonst)) {
|
||||
/* note: might already be Strangled (via #wizintrinsic) */
|
||||
if (can_be_strangled(&gy.youmonst) && !Strangled) {
|
||||
makeknown(AMULET_OF_STRANGULATION);
|
||||
Strangled = 6L;
|
||||
disp.botl = TRUE;
|
||||
on_msg(uamul);
|
||||
on_msg_done = TRUE;
|
||||
pline("It constricts your throat!");
|
||||
}
|
||||
break;
|
||||
case AMULET_OF_RESTFUL_SLEEP: {
|
||||
long newnap = (long) rnd(100), oldnap = (HSleepy & TIMEOUT);
|
||||
long newnap = (long) rnd(98) + 2L, oldnap = (HSleepy & TIMEOUT);
|
||||
|
||||
/* avoid clobbering FROMOUTSIDE bit, which might have
|
||||
gotten set by previously eating one of these amulets */
|
||||
if (newnap < oldnap || oldnap == 0L)
|
||||
/* avoid clobbering FROMOUTSIDE bit, which might have
|
||||
gotten set by previously eating one of these amulets */
|
||||
HSleepy = (HSleepy & ~TIMEOUT) | newnap;
|
||||
break;
|
||||
}
|
||||
@@ -1021,6 +1041,8 @@ Amulet_on(void)
|
||||
|
||||
if (!already_flying) {
|
||||
makeknown(AMULET_OF_FLYING);
|
||||
on_msg(uamul);
|
||||
on_msg_done = TRUE;
|
||||
disp.botl = TRUE; /* status: 'Fly' On */
|
||||
You("are now in flight.");
|
||||
}
|
||||
@@ -1033,19 +1055,28 @@ Amulet_on(void)
|
||||
case AMULET_OF_YENDOR:
|
||||
break;
|
||||
}
|
||||
|
||||
if (!on_msg_done)
|
||||
on_msg(uamul);
|
||||
}
|
||||
|
||||
void
|
||||
Amulet_off(void)
|
||||
{
|
||||
struct obj *amul = uamul; /* for off_msg() after setworn(NULL,W_AMUL) */
|
||||
boolean mkn = FALSE, early_off_msg = FALSE;
|
||||
|
||||
svc.context.takeoff.mask &= ~W_AMUL;
|
||||
|
||||
switch (uamul->otyp) {
|
||||
case AMULET_OF_ESP:
|
||||
/* need to update ability before calling see_monsters() */
|
||||
setworn((struct obj *) 0, W_AMUL);
|
||||
off_msg(amul);
|
||||
early_off_msg = TRUE;
|
||||
|
||||
see_monsters();
|
||||
return;
|
||||
break;
|
||||
case AMULET_OF_LIFE_SAVING:
|
||||
case AMULET_VERSUS_POISON:
|
||||
case AMULET_OF_REFLECTION:
|
||||
@@ -1054,21 +1085,31 @@ Amulet_off(void)
|
||||
case FAKE_AMULET_OF_YENDOR:
|
||||
break;
|
||||
case AMULET_OF_MAGICAL_BREATHING:
|
||||
/* amulet is currently still on; take it off before calling drown()
|
||||
and region_danger(); call off_msg() before specific messages */
|
||||
setworn((struct obj *) 0, W_AMUL);
|
||||
off_msg(amul); /* 'uamul' has been set to Null */
|
||||
early_off_msg = TRUE;
|
||||
|
||||
if (Underwater) {
|
||||
/* HMagical_breathing must be set off before calling drown() */
|
||||
setworn((struct obj *) 0, W_AMUL);
|
||||
if (!cant_drown(gy.youmonst.data) && !Swimming) {
|
||||
You("suddenly inhale an unhealthy amount of %s!",
|
||||
hliquid("water"));
|
||||
mkn = TRUE; /* in case of life-saving */
|
||||
(void) drown();
|
||||
}
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* FIXME: we need a poison gas region check here
|
||||
*/
|
||||
if (region_danger()) {
|
||||
/* "breathing": wouldn't get here otherwise */
|
||||
You("are breathing poison gas!");
|
||||
mkn = TRUE;
|
||||
}
|
||||
break;
|
||||
case AMULET_OF_STRANGULATION:
|
||||
setworn((struct obj *) 0, W_AMUL);
|
||||
off_msg(amul);
|
||||
early_off_msg = TRUE;
|
||||
|
||||
if (Strangled) {
|
||||
Strangled = 0L;
|
||||
disp.botl = TRUE;
|
||||
@@ -1076,6 +1117,7 @@ Amulet_off(void)
|
||||
Your("%s is no longer constricted!", body_part(NECK));
|
||||
else
|
||||
You("can breathe more easily!");
|
||||
mkn = TRUE;
|
||||
}
|
||||
break;
|
||||
case AMULET_OF_RESTFUL_SLEEP:
|
||||
@@ -1083,20 +1125,24 @@ Amulet_off(void)
|
||||
/* HSleepy = 0L; -- avoid clobbering FROMOUTSIDE bit */
|
||||
if (!ESleepy && !(HSleepy & ~TIMEOUT))
|
||||
HSleepy &= ~TIMEOUT; /* clear timeout bits */
|
||||
return;
|
||||
break;
|
||||
case AMULET_OF_FLYING: {
|
||||
boolean was_flying = !!Flying;
|
||||
|
||||
/* remove amulet 'early' to determine whether Flying changes */
|
||||
/* remove amulet 'early' to determine whether Flying changes;
|
||||
also in case spoteffects() does something with the amulet */
|
||||
setworn((struct obj *) 0, W_AMUL);
|
||||
off_msg(amul);
|
||||
early_off_msg = TRUE;
|
||||
|
||||
float_vs_flight(); /* probably not needed here */
|
||||
if (was_flying && !Flying) {
|
||||
makeknown(AMULET_OF_FLYING);
|
||||
disp.botl = TRUE; /* status: 'Fly' Off */
|
||||
You("%s.", (is_pool_or_lava(u.ux, u.uy)
|
||||
|| Is_waterlevel(&u.uz) || Is_airlevel(&u.uz))
|
||||
? "stop flying"
|
||||
: "land");
|
||||
mkn = TRUE; /* makeknown(AMULET_OF_FLYING) */
|
||||
spoteffects(TRUE);
|
||||
}
|
||||
break;
|
||||
@@ -1107,7 +1153,12 @@ Amulet_off(void)
|
||||
case AMULET_OF_YENDOR:
|
||||
break;
|
||||
}
|
||||
|
||||
setworn((struct obj *) 0, W_AMUL);
|
||||
if (!early_off_msg)
|
||||
off_msg(amul); /* (not 'uamul'; it's Null now) */
|
||||
if (mkn)
|
||||
makeknown(amul->otyp);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1198,7 +1249,9 @@ Ring_on(struct obj *obj)
|
||||
case RIN_FREE_ACTION:
|
||||
case RIN_SLOW_DIGESTION:
|
||||
case RIN_SUSTAIN_ABILITY:
|
||||
break;
|
||||
case MEAT_RING:
|
||||
/* wearing a meat ring does not affect vegan conduct */
|
||||
break;
|
||||
case RIN_STEALTH:
|
||||
toggle_stealth(obj, oldprop, TRUE);
|
||||
@@ -1383,8 +1436,7 @@ Blindf_on(struct obj *otmp)
|
||||
boolean already_blind = Blind, changed = FALSE;
|
||||
|
||||
/* blindfold might be wielded; release it for wearing */
|
||||
if (otmp->owornmask & W_WEAPONS)
|
||||
remove_worn_item(otmp, FALSE);
|
||||
remove_worn_item(otmp, FALSE);
|
||||
setworn(otmp, W_TOOL);
|
||||
on_msg(otmp);
|
||||
|
||||
@@ -1469,7 +1521,7 @@ set_wear(
|
||||
if (!obj ? uleft != 0 : (obj == uleft))
|
||||
(void) Ring_on(uleft);
|
||||
if (!obj ? uamul != 0 : (obj == uamul))
|
||||
(void) Amulet_on();
|
||||
(void) Amulet_on(uamul);
|
||||
|
||||
if (!obj ? uarmu != 0 : (obj == uarmu))
|
||||
(void) Shirt_on();
|
||||
@@ -1606,8 +1658,8 @@ cancel_don(void)
|
||||
|
||||
/* called by steal() during theft from hero; interrupt donning/doffing */
|
||||
int
|
||||
stop_donning(struct obj *stolenobj) /* no message if stolenobj is already
|
||||
being doffing */
|
||||
stop_donning(
|
||||
struct obj *stolenobj) /* no mesg if stolenobj is already being doffed */
|
||||
{
|
||||
char buf[BUFSZ];
|
||||
struct obj *otmp;
|
||||
@@ -1651,8 +1703,9 @@ static NEARDATA int Narmorpieces, Naccessories;
|
||||
|
||||
/* assign values to Narmorpieces and Naccessories */
|
||||
staticfn void
|
||||
count_worn_stuff(struct obj **which, /* caller wants this when count is 1 */
|
||||
boolean accessorizing)
|
||||
count_worn_stuff(
|
||||
struct obj **which, /* caller wants this when count is 1 */
|
||||
boolean accessorizing)
|
||||
{
|
||||
struct obj *otmp;
|
||||
|
||||
@@ -1736,12 +1789,12 @@ armor_or_accessory_off(struct obj *obj)
|
||||
off_msg(obj);
|
||||
Ring_off(obj);
|
||||
} else if (obj == uamul) {
|
||||
Amulet_off();
|
||||
off_msg(obj);
|
||||
Amulet_off(); /* does its own off_msg */
|
||||
} else if (obj == ublindf) {
|
||||
Blindf_off(obj); /* does its own off_msg */
|
||||
} else {
|
||||
impossible("removing strange accessory?");
|
||||
impossible("removing strange accessory: %s",
|
||||
safe_typename(obj->otyp));
|
||||
if (obj->owornmask)
|
||||
remove_worn_item(obj, FALSE);
|
||||
}
|
||||
@@ -2014,12 +2067,12 @@ canwearobj(struct obj *otmp, long *mask, boolean noisy)
|
||||
You("have no feet..."); /* not body_part(FOOT) */
|
||||
err++;
|
||||
} else if (Upolyd && gy.youmonst.data->mlet == S_CENTAUR) {
|
||||
/* break_armor() pushes boots off for centaurs,
|
||||
so don't let dowear() put them back on... */
|
||||
/* break_armor() pushes boots off for centaurs, so don't let
|
||||
dowear() put them back on;
|
||||
makeplural(body_part(FOOT)) would yield "rear hooves" here,
|
||||
which sounds odd, so use hard-coded "hooves" */
|
||||
if (noisy)
|
||||
You("have too many hooves to wear %s.",
|
||||
c_boots); /* makeplural(body_part(FOOT)) yields
|
||||
"rear hooves" which sounds odd */
|
||||
You("have too many hooves to wear %s.", c_boots);
|
||||
err++;
|
||||
} else if (u.utrap
|
||||
&& (u.utraptype == TT_BEARTRAP || u.utraptype == TT_INFLOOR
|
||||
@@ -2114,7 +2167,7 @@ staticfn int
|
||||
accessory_or_armor_on(struct obj *obj)
|
||||
{
|
||||
long mask = 0L;
|
||||
boolean armor, ring, eyewear;
|
||||
boolean armor, ring, amulet, eyewear;
|
||||
|
||||
if (obj->owornmask & (W_ACCESSORY | W_ARMOR)) {
|
||||
already_wearing(c_that_);
|
||||
@@ -2122,6 +2175,7 @@ accessory_or_armor_on(struct obj *obj)
|
||||
}
|
||||
armor = (obj->oclass == ARMOR_CLASS);
|
||||
ring = (obj->oclass == RING_CLASS || obj->otyp == MEAT_RING);
|
||||
amulet = (obj->oclass == AMULET_CLASS);
|
||||
eyewear = (obj->otyp == BLINDFOLD || obj->otyp == TOWEL
|
||||
|| obj->otyp == LENSES);
|
||||
/* checks which are performed prior to actually touching the item */
|
||||
@@ -2219,7 +2273,7 @@ accessory_or_armor_on(struct obj *obj)
|
||||
return res ? ECMD_TIME : ECMD_OK;
|
||||
}
|
||||
}
|
||||
} else if (obj->oclass == AMULET_CLASS) {
|
||||
} else if (amulet) {
|
||||
if (uamul) {
|
||||
already_wearing("an amulet");
|
||||
return ECMD_OK;
|
||||
@@ -2306,26 +2360,24 @@ accessory_or_armor_on(struct obj *obj)
|
||||
}
|
||||
svc.context.takeoff.mask = svc.context.takeoff.what = 0L;
|
||||
} else { /* not armor */
|
||||
boolean give_feedback = FALSE;
|
||||
|
||||
/* [releasing wielded accessory handled in Xxx_on()] */
|
||||
if (ring) {
|
||||
/* Ring_on() expects ring to already be worn as uleft or uright */
|
||||
setworn(obj, mask);
|
||||
Ring_on(obj);
|
||||
give_feedback = TRUE;
|
||||
} else if (obj->oclass == AMULET_CLASS) {
|
||||
setworn(obj, W_AMUL);
|
||||
Amulet_on();
|
||||
/* no feedback here if amulet of change got used up */
|
||||
give_feedback = (uamul != 0);
|
||||
/* is_worn(): 'obj' will always be worn here except when putting
|
||||
on a ring of levitation while at a sink location */
|
||||
if (is_worn(obj))
|
||||
on_msg(obj);
|
||||
} else if (amulet) {
|
||||
/* setworn() and on_msg() handled by Amulet_on() */
|
||||
Amulet_on(obj);
|
||||
} else if (eyewear) {
|
||||
/* setworn() handled by Blindf_on() */
|
||||
/* setworn() and on_msg() handled by Blindf_on() */
|
||||
Blindf_on(obj);
|
||||
/* message handled by Blindf_on(); leave give_feedback False */
|
||||
} else {
|
||||
impossible("putting on unexpected type of accessory: %s",
|
||||
safe_typename(obj->otyp));
|
||||
}
|
||||
/* feedback for ring or for amulet other than 'change' */
|
||||
if (give_feedback && is_worn(obj))
|
||||
prinv((char *) 0, obj, 0L);
|
||||
}
|
||||
return ECMD_TIME;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user