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
|
||||
sometimes rings dropped into sinks can be found in the pipes
|
||||
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
|
||||
|
||||
44
src/mkobj.c
44
src/mkobj.c
@@ -223,6 +223,7 @@ boolean init, artif;
|
||||
return otmp;
|
||||
}
|
||||
|
||||
/* mkobj(): select a type of item from a class, use mksobj() to create it */
|
||||
struct obj *
|
||||
mkobj(oclass, artif)
|
||||
char oclass;
|
||||
@@ -277,7 +278,7 @@ struct obj *box;
|
||||
n = 0;
|
||||
break;
|
||||
}
|
||||
/*else FALLTHRU*/
|
||||
/*else FALLTHRU*/
|
||||
case BAG_OF_HOLDING:
|
||||
n = 1;
|
||||
break;
|
||||
@@ -712,6 +713,7 @@ static const char dknowns[] = { WAND_CLASS, RING_CLASS, POTION_CLASS,
|
||||
SCROLL_CLASS, GEM_CLASS, SPBOOK_CLASS,
|
||||
WEAPON_CLASS, TOOL_CLASS, 0 };
|
||||
|
||||
/* mksobj(): create a specific type of object */
|
||||
struct obj *
|
||||
mksobj(otyp, init, artif)
|
||||
int otyp;
|
||||
@@ -743,7 +745,7 @@ boolean artif;
|
||||
otmp->cknown = 0;
|
||||
otmp->corpsenm = NON_PM;
|
||||
|
||||
if (init)
|
||||
if (init) {
|
||||
switch (let) {
|
||||
case WEAPON_CLASS:
|
||||
otmp->quan = is_multigen(otmp) ? (long) rn1(6, 6) : 1L;
|
||||
@@ -773,9 +775,8 @@ boolean artif;
|
||||
&& (--tryct > 0));
|
||||
if (tryct == 0) {
|
||||
/* perhaps rndmonnum() only wants to make G_NOCORPSE
|
||||
monsters on
|
||||
this level; let's create an adventurer's corpse
|
||||
instead, then */
|
||||
monsters on this level; create an adventurer's
|
||||
corpse instead, then */
|
||||
otmp->corpsenm = PM_HUMAN;
|
||||
}
|
||||
/* timer set below */
|
||||
@@ -889,14 +890,13 @@ boolean artif;
|
||||
case BAG_OF_TRICKS:
|
||||
otmp->spe = rnd(20);
|
||||
break;
|
||||
case FIGURINE: {
|
||||
int tryct2 = 0;
|
||||
case FIGURINE:
|
||||
tryct = 0;
|
||||
do
|
||||
otmp->corpsenm = rndmonnum();
|
||||
while (is_human(&mons[otmp->corpsenm]) && tryct2++ < 30);
|
||||
while (is_human(&mons[otmp->corpsenm]) && tryct++ < 30);
|
||||
blessorcurse(otmp, 4);
|
||||
break;
|
||||
}
|
||||
case BELL_OF_OPENING:
|
||||
otmp->spe = 3;
|
||||
break;
|
||||
@@ -918,15 +918,12 @@ boolean artif;
|
||||
curse(otmp);
|
||||
} else
|
||||
blessorcurse(otmp, 10);
|
||||
break;
|
||||
case VENOM_CLASS:
|
||||
case CHAIN_CLASS:
|
||||
case BALL_CLASS:
|
||||
break;
|
||||
case POTION_CLASS:
|
||||
otmp->fromsink = 0;
|
||||
if (otmp->otyp == POT_OIL)
|
||||
otmp->age = MAX_OIL_IN_FLASK; /* amount of oil */
|
||||
/* fall through */
|
||||
case POTION_CLASS: /* note: potions get some additional init below */
|
||||
case SCROLL_CLASS:
|
||||
#ifdef MAIL
|
||||
if (otmp->otyp != SCR_MAIL)
|
||||
@@ -1012,27 +1009,36 @@ boolean artif;
|
||||
objects[otmp->otyp].oc_class);
|
||||
return (struct obj *) 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:
|
||||
if (otmp->corpsenm == NON_PM) {
|
||||
otmp->corpsenm = undead_to_corpse(rndmonnum());
|
||||
if (mvitals[otmp->corpsenm].mvflags & (G_NOCORPSE | G_GONE))
|
||||
otmp->corpsenm = urole.malenum;
|
||||
}
|
||||
/*FALLTHRU*/
|
||||
/*FALLTHRU*/
|
||||
case STATUE:
|
||||
case FIGURINE:
|
||||
if (otmp->corpsenm == NON_PM)
|
||||
otmp->corpsenm = rndmonnum();
|
||||
/*FALLTHRU*/
|
||||
/*FALLTHRU*/
|
||||
case EGG:
|
||||
/* case TIN: */
|
||||
/* case TIN: */
|
||||
set_corpsenm(otmp, otmp->corpsenm);
|
||||
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:
|
||||
otmp->leashmon = 0;
|
||||
otmp->leashmon = 0; /* overloads corpsenm, which was set to NON_PM */
|
||||
break;
|
||||
case SPE_NOVEL:
|
||||
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
|
||||
object's glyph will have been replaced by whatever is present
|
||||
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 */
|
||||
&& !iflags.terrainmode) /* so don't set dknown when in terrain mode */
|
||||
otmp->dknown = 1; /* if a pile, clearly see the top item only */
|
||||
|
||||
Reference in New Issue
Block a user