fix #H6338 - naming mimicked potion
Player tried to #name a potion on the floor and got prompted to call a stream of fluid (sink feedback) instead of a potion. A mimic posing as an object is represented by a partially initialized object when examining its map location. #name for floor object uses the same data as look_at. obj->fromsink overloads obj->corpsenm which is set to NON_PM (-1) even when creating a non-init'd object. 'fromsink' was only being forced to 0 when creating an init'd object (unlike leash which has its overload of corpsenm set properly regardless of caller's request to init). So docall() treated a mimicked potion as a sink stream. The fix is straightforward but has pointed out another bug which is harder to fix. Examining a floor object next to you sets that obj's dknown flag as if you had seen it up close (a new feature in 3.6.0). But a mimicked item is discarded as soon as it's been looked at, so looking again from a non-adjacent spot will give different feedback since the previously set dknown will be unset when replaced by a new fake object. So you can use '/' and ';' to recognize mimics without provoking them into motion. Best fix: mimicking an object should use a fully initialized one which is tracked via monst->mextra, but that will break save file compatibility. Possible hack: change monst-> mappearance into a mask which uses N bits for object type (instead of full 'int') and one of the other bits to track obj->dknown. Examining an adjacent object probably ought to set bknown for priests, so bknown and blessed/uncursed/cursed would need to be tracked too.
This commit is contained in:
@@ -464,6 +464,8 @@ improve #adjust command's handling of the '$' and '#' inventory slots
|
|||||||
prevent #adjust from allowing anything to be moved into the special '-' slot
|
prevent #adjust from allowing anything to be moved into the special '-' slot
|
||||||
sometimes rings dropped into sinks can be found in the pipes
|
sometimes rings dropped into sinks can be found in the pipes
|
||||||
doors in special levels were always generated in vertical orientation
|
doors in special levels were always generated in vertical orientation
|
||||||
|
assigning a type name to a potion on the floor which is actually a mimic could
|
||||||
|
prompt "Call a stream of <potion-type> fluid:" (bogus 'fromsink')
|
||||||
|
|
||||||
|
|
||||||
Fixes to Post-3.6.0 Problems that Were Exposed Via git Repository
|
Fixes to Post-3.6.0 Problems that Were Exposed Via git Repository
|
||||||
|
|||||||
44
src/mkobj.c
44
src/mkobj.c
@@ -223,6 +223,7 @@ boolean init, artif;
|
|||||||
return otmp;
|
return otmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* mkobj(): select a type of item from a class, use mksobj() to create it */
|
||||||
struct obj *
|
struct obj *
|
||||||
mkobj(oclass, artif)
|
mkobj(oclass, artif)
|
||||||
char oclass;
|
char oclass;
|
||||||
@@ -277,7 +278,7 @@ struct obj *box;
|
|||||||
n = 0;
|
n = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/*else FALLTHRU*/
|
/*else FALLTHRU*/
|
||||||
case BAG_OF_HOLDING:
|
case BAG_OF_HOLDING:
|
||||||
n = 1;
|
n = 1;
|
||||||
break;
|
break;
|
||||||
@@ -712,6 +713,7 @@ static const char dknowns[] = { WAND_CLASS, RING_CLASS, POTION_CLASS,
|
|||||||
SCROLL_CLASS, GEM_CLASS, SPBOOK_CLASS,
|
SCROLL_CLASS, GEM_CLASS, SPBOOK_CLASS,
|
||||||
WEAPON_CLASS, TOOL_CLASS, 0 };
|
WEAPON_CLASS, TOOL_CLASS, 0 };
|
||||||
|
|
||||||
|
/* mksobj(): create a specific type of object */
|
||||||
struct obj *
|
struct obj *
|
||||||
mksobj(otyp, init, artif)
|
mksobj(otyp, init, artif)
|
||||||
int otyp;
|
int otyp;
|
||||||
@@ -743,7 +745,7 @@ boolean artif;
|
|||||||
otmp->cknown = 0;
|
otmp->cknown = 0;
|
||||||
otmp->corpsenm = NON_PM;
|
otmp->corpsenm = NON_PM;
|
||||||
|
|
||||||
if (init)
|
if (init) {
|
||||||
switch (let) {
|
switch (let) {
|
||||||
case WEAPON_CLASS:
|
case WEAPON_CLASS:
|
||||||
otmp->quan = is_multigen(otmp) ? (long) rn1(6, 6) : 1L;
|
otmp->quan = is_multigen(otmp) ? (long) rn1(6, 6) : 1L;
|
||||||
@@ -773,9 +775,8 @@ boolean artif;
|
|||||||
&& (--tryct > 0));
|
&& (--tryct > 0));
|
||||||
if (tryct == 0) {
|
if (tryct == 0) {
|
||||||
/* perhaps rndmonnum() only wants to make G_NOCORPSE
|
/* perhaps rndmonnum() only wants to make G_NOCORPSE
|
||||||
monsters on
|
monsters on this level; create an adventurer's
|
||||||
this level; let's create an adventurer's corpse
|
corpse instead, then */
|
||||||
instead, then */
|
|
||||||
otmp->corpsenm = PM_HUMAN;
|
otmp->corpsenm = PM_HUMAN;
|
||||||
}
|
}
|
||||||
/* timer set below */
|
/* timer set below */
|
||||||
@@ -889,14 +890,13 @@ boolean artif;
|
|||||||
case BAG_OF_TRICKS:
|
case BAG_OF_TRICKS:
|
||||||
otmp->spe = rnd(20);
|
otmp->spe = rnd(20);
|
||||||
break;
|
break;
|
||||||
case FIGURINE: {
|
case FIGURINE:
|
||||||
int tryct2 = 0;
|
tryct = 0;
|
||||||
do
|
do
|
||||||
otmp->corpsenm = rndmonnum();
|
otmp->corpsenm = rndmonnum();
|
||||||
while (is_human(&mons[otmp->corpsenm]) && tryct2++ < 30);
|
while (is_human(&mons[otmp->corpsenm]) && tryct++ < 30);
|
||||||
blessorcurse(otmp, 4);
|
blessorcurse(otmp, 4);
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
case BELL_OF_OPENING:
|
case BELL_OF_OPENING:
|
||||||
otmp->spe = 3;
|
otmp->spe = 3;
|
||||||
break;
|
break;
|
||||||
@@ -918,15 +918,12 @@ boolean artif;
|
|||||||
curse(otmp);
|
curse(otmp);
|
||||||
} else
|
} else
|
||||||
blessorcurse(otmp, 10);
|
blessorcurse(otmp, 10);
|
||||||
|
break;
|
||||||
case VENOM_CLASS:
|
case VENOM_CLASS:
|
||||||
case CHAIN_CLASS:
|
case CHAIN_CLASS:
|
||||||
case BALL_CLASS:
|
case BALL_CLASS:
|
||||||
break;
|
break;
|
||||||
case POTION_CLASS:
|
case POTION_CLASS: /* note: potions get some additional init below */
|
||||||
otmp->fromsink = 0;
|
|
||||||
if (otmp->otyp == POT_OIL)
|
|
||||||
otmp->age = MAX_OIL_IN_FLASK; /* amount of oil */
|
|
||||||
/* fall through */
|
|
||||||
case SCROLL_CLASS:
|
case SCROLL_CLASS:
|
||||||
#ifdef MAIL
|
#ifdef MAIL
|
||||||
if (otmp->otyp != SCR_MAIL)
|
if (otmp->otyp != SCR_MAIL)
|
||||||
@@ -1012,27 +1009,36 @@ boolean artif;
|
|||||||
objects[otmp->otyp].oc_class);
|
objects[otmp->otyp].oc_class);
|
||||||
return (struct obj *) 0;
|
return (struct obj *) 0;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* some things must get done (corpsenm, timers) even if init = 0 */
|
/* some things must get done (corpsenm, timers) even if init = 0 */
|
||||||
switch (otmp->otyp) {
|
switch ((otmp->oclass == POTION_CLASS && otmp->otyp != POT_OIL)
|
||||||
|
? POT_WATER
|
||||||
|
: otmp->otyp) {
|
||||||
case CORPSE:
|
case CORPSE:
|
||||||
if (otmp->corpsenm == NON_PM) {
|
if (otmp->corpsenm == NON_PM) {
|
||||||
otmp->corpsenm = undead_to_corpse(rndmonnum());
|
otmp->corpsenm = undead_to_corpse(rndmonnum());
|
||||||
if (mvitals[otmp->corpsenm].mvflags & (G_NOCORPSE | G_GONE))
|
if (mvitals[otmp->corpsenm].mvflags & (G_NOCORPSE | G_GONE))
|
||||||
otmp->corpsenm = urole.malenum;
|
otmp->corpsenm = urole.malenum;
|
||||||
}
|
}
|
||||||
/*FALLTHRU*/
|
/*FALLTHRU*/
|
||||||
case STATUE:
|
case STATUE:
|
||||||
case FIGURINE:
|
case FIGURINE:
|
||||||
if (otmp->corpsenm == NON_PM)
|
if (otmp->corpsenm == NON_PM)
|
||||||
otmp->corpsenm = rndmonnum();
|
otmp->corpsenm = rndmonnum();
|
||||||
/*FALLTHRU*/
|
/*FALLTHRU*/
|
||||||
case EGG:
|
case EGG:
|
||||||
/* case TIN: */
|
/* case TIN: */
|
||||||
set_corpsenm(otmp, otmp->corpsenm);
|
set_corpsenm(otmp, otmp->corpsenm);
|
||||||
break;
|
break;
|
||||||
|
case POT_OIL:
|
||||||
|
otmp->age = MAX_OIL_IN_FLASK; /* amount of oil */
|
||||||
|
/*FALLTHRU*/
|
||||||
|
case POT_WATER: /* POTION_CLASS */
|
||||||
|
otmp->fromsink = 0; /* overloads corpsenm, which was set to NON_PM */
|
||||||
|
break;
|
||||||
case LEASH:
|
case LEASH:
|
||||||
otmp->leashmon = 0;
|
otmp->leashmon = 0; /* overloads corpsenm, which was set to NON_PM */
|
||||||
break;
|
break;
|
||||||
case SPE_NOVEL:
|
case SPE_NOVEL:
|
||||||
otmp->novelidx = -1; /* "none of the above"; will be changed */
|
otmp->novelidx = -1; /* "none of the above"; will be changed */
|
||||||
|
|||||||
@@ -195,7 +195,7 @@ struct obj **obj_p;
|
|||||||
glyph among floor and buried objects; when !Blind, any buried
|
glyph among floor and buried objects; when !Blind, any buried
|
||||||
object's glyph will have been replaced by whatever is present
|
object's glyph will have been replaced by whatever is present
|
||||||
on the surface as soon as we moved next to its spot */
|
on the surface as soon as we moved next to its spot */
|
||||||
&& otmp->where == OBJ_FLOOR /* not buried */
|
&& (fakeobj || otmp->where == OBJ_FLOOR) /* not buried */
|
||||||
/* terrain mode views what's already known, doesn't learn new stuff */
|
/* terrain mode views what's already known, doesn't learn new stuff */
|
||||||
&& !iflags.terrainmode) /* so don't set dknown when in terrain mode */
|
&& !iflags.terrainmode) /* so don't set dknown when in terrain mode */
|
||||||
otmp->dknown = 1; /* if a pile, clearly see the top item only */
|
otmp->dknown = 1; /* if a pile, clearly see the top item only */
|
||||||
|
|||||||
Reference in New Issue
Block a user